From 599fd8abe032fb7e21ced64c451ffdf763345fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Strz=C4=99ba=C5=82a?= Date: Thu, 9 Aug 2018 14:41:40 +0200 Subject: [PATCH 001/182] =?UTF-8?q?Spec=20file=20for=20building=20under=20?= =?UTF-8?q?MERSDK=20(sailfishos)=20Signed-off-by:=20Wiktor=20Strz=C4=99ba?= =?UTF-8?q?=C5=82a=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/sailfishos/retroarch-sailfishos.spec | 87 ++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 pkg/sailfishos/retroarch-sailfishos.spec diff --git a/pkg/sailfishos/retroarch-sailfishos.spec b/pkg/sailfishos/retroarch-sailfishos.spec new file mode 100644 index 0000000000..e5e54448b2 --- /dev/null +++ b/pkg/sailfishos/retroarch-sailfishos.spec @@ -0,0 +1,87 @@ +Name: retroarch +Version: 1.7.3 +Release: v1.2 +Summary: Official reference frontend for libretro + +Group: Applications/Emulators +License: GPLv3+ +URL: http://www.libretro.com/ + +BuildRequires: libxml2-devel +BuildRequires: mesa-llvmpipe-libwayland-egl-devel +BuildRequires: pulseaudio-devel +BuildRequires: OpenAL-devel +BuildRequires: libxkbcommon-devel +BuildRequires: zlib-devel +BuildRequires: freetype-devel +#BuildRequires: ffmpeg-devel +BuildRequires: SDL2-devel +BuildRequires: SDL2_image-devel +#Requires libusb 1.0.16 +#BuildRequires: libusb-devel + +%description +RetroArch is the official reference frontend for the libretro API. +Libretro is a simple but powerful development interface that allows for the +easy creation of emulators, games and multimedia applications that can plug +straight into any libretro-compatible frontend. This development interface +is open to others so that they can run these pluggable emulator and game +cores also in their own programs or devices. + +%build +# No autotools, custom configure script +%ifarch armv7hl +./configure --prefix=%{_prefix} --enable-opengles --enable-neon --enable-egl --enable-wayland +%else +./configure --prefix=%{_prefix} --enable-gles +%endif +make %{?_smp_mflags} + + +%install +make install DESTDIR=%{buildroot} +# Configuration changes +sed -i \ + 's|^# libretro_directory =.*|libretro_directory = "~/.config/retroarch/cores/"|; + s|^# libretro_info_path =.*|libretro_info_path = "~/.config/retroarch/cores/"|; + s|^# joypad_autoconfig_dir =.*|joypad_autoconfig_dir = "/etc/retroarch/joypad"|; + s|^# video_fullscreen =.*|video_fullscreen = "true"|; + s|^# menu_driver =.*|menu_driver = "glui"|; + s|^# menu_pointer_enable =.*|menu_pointer_enable = "true"|; + s|^# input_driver =.*|input_driver = "wayland"|' \ + %{buildroot}/etc/retroarch.cfg + +%ifarch armv7hl +sed -i \ + 's|^# core_updater_buildbot_url =.*|core_updater_buildbot_url = "http://buildbot.libretro.com/nightly/linux/armhf/latest/"|;' \ + %{buildroot}/etc/retroarch.cfg +%endif + +#Disabling audio till it's fixed +sed -i \ + 's|^# audio_enable.*|audio_enable = "false"|' \ + %{buildroot}/etc/retroarch.cfg + +sed -i \ + 's|^Exec=retroarch|Exec=retroarch --menu|' \ + %{buildroot}/usr/share/applications/retroarch.desktop + + # Install icon file in the correct place + mkdir -p %{buildroot}/usr/share/icons/hicolor/86x86/apps + install -m 644 "./media/retroarch-96x96.png" "%{buildroot}/usr/share/icons/hicolor/86x86/apps/retroarch.png" + rm "%{buildroot}/usr/share/pixmaps/retroarch.svg" + rmdir "%{buildroot}/usr/share/pixmaps" + +%files +%doc README.md +%config /etc/retroarch.cfg +%{_prefix}/bin/retroarch +%{_prefix}/bin/retroarch-cg2glsl +%{_prefix}/share/applications/retroarch.desktop +%{_prefix}/share/man/man6/*.6* +%{_prefix}/share/icons/hicolor/86x86/apps/retroarch.* +%{_prefix}/share/doc/retroarch/* +%changelog + + + From ca769b0006fbbdc295cd816835b91e9e6212c640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Strz=C4=99ba=C5=82a?= Date: Thu, 9 Aug 2018 14:42:19 +0200 Subject: [PATCH 002/182] Wayland have EGL libs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Wiktor Strzębała --- Makefile.common | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.common b/Makefile.common index 3cd2c39654..5f4106db23 100644 --- a/Makefile.common +++ b/Makefile.common @@ -960,6 +960,9 @@ endif ifeq ($(HAVE_WAYLAND), 1) OBJ += gfx/drivers_context/wayland_ctx.o \ input/drivers/wayland_input.o + ifeq ($(HAVE_EGL), 1) + LIBS += $(EGL_LIBS) + endif DEFINES += $(WAYLAND_CFLAGS) $(WAYLAND_CURSOR_CFLAGS) LIBS += $(WAYLAND_LIBS) $(WAYLAND_CURSOR_LIBS) endif From 45799ee034c18fb62e811093ffa3890d10d82a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Strz=C4=99ba=C5=82a?= Date: Thu, 9 Aug 2018 20:49:27 +0200 Subject: [PATCH 003/182] Bring up touch support for wayland subsystem for sailfish os devices Touch code cleanup Make variabled static as suggest bparker06 C89 compilation error fix (at least for loops) More C89 fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Wiktor Strzębała --- gfx/common/wayland_common.h | 13 +++ gfx/drivers_context/wayland_ctx.c | 187 +++++++++++++++++++++++++++++- input/drivers/wayland_input.c | 91 ++++++++++++++- 3 files changed, 287 insertions(+), 4 deletions(-) diff --git a/gfx/common/wayland_common.h b/gfx/common/wayland_common.h index e48f450907..3cbedb9048 100644 --- a/gfx/common/wayland_common.h +++ b/gfx/common/wayland_common.h @@ -28,6 +28,16 @@ #define UDEV_KEY_MAX 0x2ff #define UDEV_MAX_KEYS (UDEV_KEY_MAX + 7) / 8 +#define MAX_TOUCHES 16 + +typedef struct +{ + bool active; + int16_t x; + int16_t y; +} wayland_touch_data_t; + + typedef struct input_ctx_wayland_data { /* Wayland uses Linux keysyms. */ @@ -49,6 +59,9 @@ typedef struct input_ctx_wayland_data const input_device_driver_t *joypad; bool blocked; + + wayland_touch_data_t touches[MAX_TOUCHES]; + } input_ctx_wayland_data_t; #endif diff --git a/gfx/drivers_context/wayland_ctx.c b/gfx/drivers_context/wayland_ctx.c index 2462fc5ef0..7778e6c280 100644 --- a/gfx/drivers_context/wayland_ctx.c +++ b/gfx/drivers_context/wayland_ctx.c @@ -51,6 +51,19 @@ #include "../../input/input_driver.h" #include "../../input/input_keymaps.h" + +typedef struct touch_pos +{ + bool active; + int32_t id; + unsigned x; + unsigned y; +} touch_pos_t; + +static int num_active_touches; +static touch_pos_t active_touch_positions[MAX_TOUCHES]; + + typedef struct gfx_ctx_wayland_data { #ifdef HAVE_EGL @@ -70,6 +83,7 @@ typedef struct gfx_ctx_wayland_data struct wl_shell *shell; struct wl_keyboard *wl_keyboard; struct wl_pointer *wl_pointer; + struct wl_touch *wl_touch; struct wl_seat *seat; struct wl_shm *shm; unsigned swap_interval; @@ -329,8 +343,136 @@ static const struct wl_pointer_listener pointer_listener = { pointer_handle_axis, }; +static void touch_handle_down(void *data, + struct wl_touch *wl_touch, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + int32_t id, + wl_fixed_t x, + wl_fixed_t y) +{ + int i; + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + if (num_active_touches < MAX_TOUCHES) + { + for (i=0; iwl_pointer); wl->wl_pointer = NULL; } + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wl->wl_touch) + { + wl->wl_touch = wl_seat_get_touch(seat); + wl_touch_add_listener(wl->wl_touch, &touch_listener, wl); + } + else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wl->wl_touch) + { + wl_touch_destroy(wl->wl_touch); + wl->wl_touch = NULL; + } + } static void seat_handle_name(void *data, struct wl_seat *seat, const char *name) @@ -368,6 +521,22 @@ static const struct wl_seat_listener seat_listener = { seat_handle_name, }; +/* Touch handle functions */ + +bool wayland_context_gettouchpos(void *data, unsigned id, + unsigned* touch_x, unsigned* touch_y) +{ + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + + if (id >= MAX_TOUCHES) + return false; + *touch_x = active_touch_positions[id].x; + *touch_y = active_touch_positions[id].y; + return active_touch_positions[id].active; +} + + + /* Shell surface callbacks. */ static void shell_surface_handle_ping(void *data, struct wl_shell_surface *shell_surface, @@ -503,7 +672,7 @@ static void registry_handle_global(void *data, struct wl_registry *reg, wl->shm = (struct wl_shm*)wl_registry_bind(reg, id, &wl_shm_interface, 1); else if (string_is_equal(interface, "wl_seat")) { - wl->seat = (struct wl_seat*)wl_registry_bind(reg, id, &wl_seat_interface, 4); + wl->seat = (struct wl_seat*)wl_registry_bind(reg, id, &wl_seat_interface, 2); wl_seat_add_listener(wl->seat, &seat_listener, wl); } } @@ -568,6 +737,8 @@ static void gfx_ctx_wl_destroy_resources(gfx_ctx_wayland_data_t *wl) wl_keyboard_destroy(wl->wl_keyboard); if (wl->wl_pointer) wl_pointer_destroy(wl->wl_pointer); + if (wl->wl_touch) + wl_touch_destroy(wl->wl_touch); if (wl->cursor.theme) wl_cursor_theme_destroy(wl->cursor.theme); @@ -776,6 +947,7 @@ static bool gfx_ctx_wl_get_metrics(void *data, static void *gfx_ctx_wl_init(video_frame_info_t *video_info, void *video_driver) { + int i; #ifdef HAVE_OPENGL static const EGLint egl_attribs_gl[] = { WL_EGL_ATTRIBS_BASE, @@ -924,12 +1096,23 @@ static void *gfx_ctx_wl_init(video_frame_info_t *video_info, void *video_driver) break; } + wl->input.keyboard_focus = true; wl->input.mouse.focus = true; wl->cursor.surface = wl_compositor_create_surface(wl->compositor); wl->cursor.theme = wl_cursor_theme_load(NULL, 16, wl->shm); wl->cursor.default_cursor = wl_cursor_theme_get_cursor(wl->cursor.theme, "left_ptr"); + + num_active_touches = 0; + for (i=0;iinput); #ifdef HAVE_DBUS diff --git a/input/drivers/wayland_input.c b/input/drivers/wayland_input.c index 0363624320..782311f090 100644 --- a/input/drivers/wayland_input.c +++ b/input/drivers/wayland_input.c @@ -50,6 +50,7 @@ /* TODO/FIXME - * fix game focus toggle */ + /* Forward declaration */ void flush_wayland_fd(void *data); @@ -98,6 +99,32 @@ static int16_t input_wl_lightgun_state(input_ctx_wayland_data_t *wl, unsigned id return 0; } +static void input_wl_touch_pool(void *data) +{ + int id; + input_ctx_wayland_data_t *wl = (input_ctx_wayland_data_t*)data; + + if (!wl) + return; + + unsigned touch_x = 0; + unsigned touch_y = 0; + + for (id=0; idtouches[id].active = true; + } + else + { + wl->touches[id].active = false; + } + wl->touches[id].x = touch_x; + wl->touches[id].y = touch_y; + } +} + static void input_wl_poll(void *data) { input_ctx_wayland_data_t *wl = (input_ctx_wayland_data_t*)data; @@ -119,6 +146,8 @@ static void input_wl_poll(void *data) if (wl->joypad) wl->joypad->poll(); + + input_wl_touch_pool(wl); } static int16_t input_wl_analog_pressed(input_ctx_wayland_data_t *wl, @@ -175,8 +204,9 @@ static int16_t input_wl_pointer_state(input_ctx_wayland_data_t *wl, vp.full_height = 0; if (!(video_driver_translate_coord_viewport_wrap(&vp, - wl->mouse.x, wl->mouse.y, + wl->mouse.x, wl->mouse.y, &res_x, &res_y, &res_screen_x, &res_screen_y))) + return 0; if (screen) @@ -203,6 +233,59 @@ static int16_t input_wl_pointer_state(input_ctx_wayland_data_t *wl, return 0; } +static int16_t input_wl_touch_state(input_ctx_wayland_data_t *wl, + unsigned idx, unsigned id, bool screen) +{ + struct video_viewport vp; + + bool inside = false; + int16_t res_x = 0; + int16_t res_y = 0; + int16_t res_screen_x = 0; + int16_t res_screen_y = 0; + + vp.x = 0; + vp.y = 0; + vp.width = 0; + vp.height = 0; + vp.full_width = 0; + vp.full_height = 0; + + if (idx > MAX_TOUCHES) + return 0; + + if (!(video_driver_translate_coord_viewport_wrap(&vp, + wl->touches[idx].x, wl->touches[idx].y, + &res_x, &res_y, &res_screen_x, &res_screen_y))) + return 0; + + if (screen) + { + res_x = res_screen_x; + res_y = res_screen_y; + } + + inside = (res_x >= -0x7fff) && (res_y >= -0x7fff); + + if (!inside) + return 0; + + switch (id) + { + case RETRO_DEVICE_ID_POINTER_X: + return res_x; + case RETRO_DEVICE_ID_POINTER_Y: + return res_y; + case RETRO_DEVICE_ID_POINTER_PRESSED: + return wl->touches[idx].active; + } + + return 0; +} + + + + static int16_t input_wl_state(void *data, rarch_joypad_info_t joypad_info, const struct retro_keybind **binds, @@ -233,11 +316,15 @@ static int16_t input_wl_state(void *data, return input_wl_mouse_state(wl, id, true); case RETRO_DEVICE_POINTER: - case RARCH_DEVICE_POINTER_SCREEN: if (idx == 0) return input_wl_pointer_state(wl, idx, id, device == RARCH_DEVICE_POINTER_SCREEN); break; + case RARCH_DEVICE_POINTER_SCREEN: + if (idx < MAX_TOUCHES) + return input_wl_touch_state(wl, idx, id, + device == RARCH_DEVICE_POINTER_SCREEN); + break; case RETRO_DEVICE_LIGHTGUN: return input_wl_lightgun_state(wl, id); } From 8bbc0cb115e2fb47d471abf264915542c9119497 Mon Sep 17 00:00:00 2001 From: alfrix Date: Sat, 4 Aug 2018 14:19:18 -0300 Subject: [PATCH 004/182] Cleanup --- menu/drivers/xmb.c | 64 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index f0511dc936..284c498ddd 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -906,7 +906,7 @@ static void xmb_update_thumbnail_path(void *data, unsigned i, char pos) xmb_node_t *node = (xmb_node_t*) file_list_get_userdata_at_offset(selection_buf, i); - if (!string_is_empty(node->fullpath) && + if (!string_is_empty(node->fullpath) && (pos == 'R' || (pos == 'L' && string_is_equal(xmb_thumbnails_ident('R'), msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))))) { @@ -937,9 +937,9 @@ static void xmb_update_thumbnail_path(void *data, unsigned i, char pos) if (string_is_equal(core_name, "imageviewer")) { if ( - (pos == 'R') || + (pos == 'R') || ( - pos == 'L' && + pos == 'L' && string_is_equal(xmb_thumbnails_ident('R'), msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)) ) @@ -1766,7 +1766,7 @@ static void xmb_list_switch(xmb_handle_t *xmb) xmb_list_switch_horizontal_list(xmb); anim_entry.duration = XMB_DELAY; - anim_entry.target_value = xmb->icon_spacing_horizontal + anim_entry.target_value = xmb->icon_spacing_horizontal * -(float)xmb->categories_selection_ptr; anim_entry.subject = &xmb->categories_x_pos; anim_entry.easing_enum = EASING_OUT_QUAD; @@ -1945,7 +1945,7 @@ static void xmb_context_reset_horizontal_list( size_t list_size = xmb_list_get_size(xmb, MENU_LIST_HORIZONTAL); - xmb->categories_x_pos = + xmb->categories_x_pos = xmb->icon_spacing_horizontal * -(float)xmb->categories_selection_ptr; @@ -2374,7 +2374,7 @@ static void xmb_calculate_visible_range(const xmb_handle_t *xmb, { for (j = current; j-- > 0; ) { - float bottom = xmb_item_y(xmb, j, current) + float bottom = xmb_item_y(xmb, j, current) + base_y + xmb->icon_size; if (bottom < 0) @@ -2984,7 +2984,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) return; scale_factor = (settings->uints.menu_xmb_scale_factor * (float)width) / (1920.0 * 100); - pseudo_font_length = xmb->icon_spacing_horizontal * 4 - xmb->icon_size / 4; + pseudo_font_length = xmb->icon_spacing_horizontal * 4 - xmb->icon_size / 4; xmb->frame_count++; @@ -3071,20 +3071,20 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) /* This is used for hiding thumbnails when going into sub-levels in the * Quick Menu as well as when selecting "Information" for a playlist entry. - * NOTE: This is currently a pretty crude check, simply going by menu depth + * NOTE: This is currently a pretty crude check, simply going by menu depth * and not specifically identifying which menu we're actually in. */ hide_thumbnails = xmb_system_tab > XMB_SYSTEM_TAB_SETTINGS && xmb->depth > 2; /* Right thumbnail big size */ if (!hide_thumbnails && !xmb->savestate_thumbnail && xmb->use_ps3_layout && - (!settings->bools.menu_xmb_vertical_thumbnails || + (!settings->bools.menu_xmb_vertical_thumbnails || (settings->bools.menu_xmb_vertical_thumbnails && !xmb->left_thumbnail))) { /* Do not draw the right thumbnail if there is no space available */ - if (((xmb->margins_screen_top + + if (((xmb->margins_screen_top + xmb->icon_size + min_thumb_size) <= height) && - ((xmb->margins_screen_left * scale_mod[5] + + ((xmb->margins_screen_left * scale_mod[5] + xmb->icon_spacing_horizontal + pseudo_font_length + min_thumb_size) <= width)) { @@ -3096,8 +3096,8 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) float thumb_width = 0.0f; float thumb_height = 0.0f; - float thumb_max_width = (float)width - (xmb->icon_size / 6) - - (xmb->margins_screen_left * scale_mod[5]) - + float thumb_max_width = (float)width - (xmb->icon_size / 6) + - (xmb->margins_screen_left * scale_mod[5]) - xmb->icon_spacing_horizontal - pseudo_font_length; #ifdef XMB_DEBUG @@ -3125,11 +3125,11 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) ((float)height * under_thumb_margin)) { thumb_width = thumb_width * - ((((float)height * under_thumb_margin) - + ((((float)height * under_thumb_margin) - xmb->margins_screen_top - xmb->icon_size) / thumb_height); thumb_height = thumb_height * - ((((float)height * under_thumb_margin) - + ((((float)height * under_thumb_margin) - xmb->margins_screen_top - xmb->icon_size) / thumb_height); } @@ -3185,19 +3185,19 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) } /* Limit left thumbnail height to screen height + margin. */ - if (xmb->margins_screen_top + xmb->icon_size * + if (xmb->margins_screen_top + xmb->icon_size * (!(xmb->depth == 1)? 2.1 : 1) + - left_thumb_height >= + left_thumb_height >= ((float)height - (96.0 * scale_factor))) { left_thumb_width = left_thumb_width * - ((((float)height - (96.0 * scale_factor)) + ((((float)height - (96.0 * scale_factor)) - xmb->margins_screen_top - (xmb->icon_size * (!(xmb->depth == 1)? 2.1 : 1))) / left_thumb_height); left_thumb_height = left_thumb_height * - ((((float)height - (96.0 * scale_factor)) + ((((float)height - (96.0 * scale_factor)) - xmb->margins_screen_top - (xmb->icon_size * (!(xmb->depth == 1)? 2.1 : 1))) / left_thumb_height); @@ -3205,9 +3205,9 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) xmb_draw_thumbnail(video_info, xmb, &coord_white[0], width, height, - (xmb->icon_size / 6) + + (xmb->icon_size / 6) + ((thumb_max_width - left_thumb_width) / 2), - xmb->margins_screen_top + xmb->icon_size * + xmb->margins_screen_top + xmb->icon_size * (!(xmb->depth == 1)? 2.1 : 1) + left_thumb_height, left_thumb_width, left_thumb_height, xmb->left_thumbnail); @@ -3220,9 +3220,9 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) { /* Do not draw the left thumbnail if there is no space available */ - if (((xmb->margins_screen_top + + if (((xmb->margins_screen_top + xmb->icon_size + min_thumb_size) <= height) && - ((xmb->margins_screen_left * scale_mod[5] + + ((xmb->margins_screen_left * scale_mod[5] + xmb->icon_spacing_horizontal + pseudo_font_length + min_thumb_size) <= width)) { @@ -3336,7 +3336,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) } xmb_draw_thumbnail(video_info, - xmb, &coord_white[0], width, height, + xmb, &coord_white[0], width, height, ((thumb_max_width - left_thumb_width) / 2), xmb->margins_screen_top + (xmb->icon_size * (!(xmb->depth == 1)? 2.2 : 0.75)) + left_thumb_height, @@ -3457,7 +3457,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) &mymat, xmb->textures.list[XMB_TEXTURE_ARROW], xmb->x + xmb->margins_screen_left + - xmb->icon_spacing_horizontal - + xmb->icon_spacing_horizontal - xmb->icon_size / 2.0 + xmb->icon_size, xmb->margins_screen_top + xmb->icon_size / 2.0 + xmb->icon_spacing_vertical @@ -3490,9 +3490,9 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) uintptr_t texture = node->icon; float x = xmb->x + xmb->categories_x_pos + xmb->margins_screen_left + - xmb->icon_spacing_horizontal + xmb->icon_spacing_horizontal * (i + 1) - xmb->icon_size / 2.0; - float y = xmb->margins_screen_top + float y = xmb->margins_screen_top + xmb->icon_size / 2.0; float rotation = 0; float scale_factor = node->zoom; @@ -3524,7 +3524,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) /* Right side 2 thumbnails on top of each other */ /* here to be displayed above the horizontal icons */ - if (!hide_thumbnails && !xmb->savestate_thumbnail && xmb->use_ps3_layout && + if (!hide_thumbnails && !xmb->savestate_thumbnail && xmb->use_ps3_layout && xmb->left_thumbnail && xmb->thumbnail && settings->bools.menu_xmb_vertical_thumbnails) { @@ -3593,9 +3593,9 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) /* Do not draw the left thumbnail if there is no space available */ - if (((xmb->margins_screen_top + + if (((xmb->margins_screen_top + xmb->icon_size + min_thumb_size) <= height) && - ((xmb->margins_screen_left * scale_mod[5] + + ((xmb->margins_screen_left * scale_mod[5] + xmb->icon_spacing_horizontal + pseudo_font_length + min_thumb_size) <= width)) { @@ -3667,7 +3667,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) xmb->selection_buf_old, xmb->selection_ptr_old, (xmb_list_get_size(xmb, MENU_LIST_PLAIN) > 1) - ? xmb->categories_selection_ptr : + ? xmb->categories_selection_ptr : xmb->categories_selection_ptr_old, &item_color[0], width, @@ -3803,7 +3803,7 @@ static void xmb_layout_psp(xmb_handle_t *xmb, int width) float scale_factor = ((settings->uints.menu_xmb_scale_factor * width) / (1920.0 * 100)) * 1.5; #ifdef _3DS - scale_factor = + scale_factor = settings->uints.menu_xmb_scale_factor / 400.0; #endif From 6e64a390442e09da84ed63463fdd3df88d3283b6 Mon Sep 17 00:00:00 2001 From: alfrix Date: Wed, 8 Aug 2018 18:47:42 -0300 Subject: [PATCH 005/182] Add icons to XMB (limited to Monochrome for now) Add monochrome inverted to the menu icons Allow the extra XMB icons in custom theme Add subsettings --- menu/drivers/xmb.c | 236 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 229 insertions(+), 7 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 284c498ddd..d01bdb9337 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -105,6 +105,8 @@ enum #ifdef HAVE_NETWORKING XMB_TEXTURE_NETPLAY, XMB_TEXTURE_ROOM, + XMB_TEXTURE_IROOM, + XMB_TEXTURE_LANROOM, #if 0 /* stub these out until we have the icons */ XMB_TEXTURE_ROOM_LAN, @@ -155,6 +157,33 @@ enum XMB_TEXTURE_KEY, XMB_TEXTURE_KEY_HOVER, XMB_TEXTURE_DIALOG_SLICE, + XMB_TEXTURE_ACHIEVEMENTS, + XMB_TEXTURE_AUDIO, + XMB_TEXTURE_EXIT, + XMB_TEXTURE_FRAMESKIP, + XMB_TEXTURE_INFO, + XMB_TEXTURE_HELP, + XMB_TEXTURE_NETWORK, + XMB_TEXTURE_POWER, + XMB_TEXTURE_SAVING, + XMB_TEXTURE_UPDATER, + XMB_TEXTURE_VIDEO, + XMB_TEXTURE_RECORD, + XMB_TEXTURE_INPUT, + XMB_TEXTURE_MIXER, + XMB_TEXTURE_LOG, + XMB_TEXTURE_OSD, + XMB_TEXTURE_UI, + XMB_TEXTURE_USER, + XMB_TEXTURE_PRIVACY, + XMB_TEXTURE_LATENCY, + XMB_TEXTURE_DRIVERS, + XMB_TEXTURE_PLAYLIST, + XMB_TEXTURE_QUICKMENU, + XMB_TEXTURE_REWIND, + XMB_TEXTURE_OVERLAY, + XMB_TEXTURE_OVERRIDE, + XMB_TEXTURE_NOTIFICATIONS, XMB_TEXTURE_LAST }; @@ -424,7 +453,6 @@ const char* xmb_theme_ident(void) default: break; } - return "monochrome"; } @@ -2211,6 +2239,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_SAVE_STATE: return xmb->textures.list[XMB_TEXTURE_SAVESTATE]; case MENU_ENUM_LABEL_LOAD_STATE: + case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET: return xmb->textures.list[XMB_TEXTURE_LOADSTATE]; case MENU_ENUM_LABEL_PARENT_DIRECTORY: case MENU_ENUM_LABEL_UNDO_LOAD_STATE: @@ -2226,17 +2255,153 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, return xmb->textures.list[XMB_TEXTURE_RENAME]; case MENU_ENUM_LABEL_RESUME_CONTENT: return xmb->textures.list[XMB_TEXTURE_RESUME]; - case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE: - case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR: - case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME: - return xmb->textures.list[XMB_TEXTURE_SAVESTATE]; case MENU_ENUM_LABEL_FAVORITES: case MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST: return xmb->textures.list[XMB_TEXTURE_FOLDER]; case MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR: return xmb->textures.list[XMB_TEXTURE_RDB]; + + + /* Menu collection submenus*/ + case MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST: + return xmb->textures.list[XMB_TEXTURE_ZIP]; + case MENU_ENUM_LABEL_GOTO_FAVORITES: + return xmb->textures.list[XMB_TEXTURE_FAVORITE]; + case MENU_ENUM_LABEL_GOTO_IMAGES: + return xmb->textures.list[XMB_TEXTURE_IMAGE]; + case MENU_ENUM_LABEL_GOTO_VIDEO: + return xmb->textures.list[XMB_TEXTURE_MOVIE]; + case MENU_ENUM_LABEL_GOTO_MUSIC: + return xmb->textures.list[XMB_TEXTURE_MUSIC]; + default: - break; + /* Menu icons are here waiting for theme support*/ + { + settings_t *settings = config_get_ptr(); + if (settings->uints.menu_xmb_theme == XMB_ICON_THEME_MONOCHROME || + settings->uints.menu_xmb_theme == XMB_ICON_THEME_MONOCHROME_INVERTED || + settings->uints.menu_xmb_theme == XMB_ICON_THEME_CUSTOM + ) + { + switch (enum_idx) + { + /* Menu icons */ + case MENU_ENUM_LABEL_CONTENT_SETTINGS: + case MENU_ENUM_LABEL_UPDATE_ASSETS: + return xmb->textures.list[XMB_TEXTURE_QUICKMENU]; + case MENU_ENUM_LABEL_CORE_LIST: + case MENU_ENUM_LABEL_CORE_SETTINGS: + case MENU_ENUM_LABEL_CORE_UPDATER_LIST: + return xmb->textures.list[XMB_TEXTURE_CORE]; + case MENU_ENUM_LABEL_LOAD_CONTENT_LIST: + case MENU_ENUM_LABEL_SCAN_FILE: + return xmb->textures.list[XMB_TEXTURE_FILE]; + case MENU_ENUM_LABEL_ONLINE_UPDATER: + case MENU_ENUM_LABEL_UPDATER_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_UPDATER]; + case MENU_ENUM_LABEL_UPDATE_LAKKA: + return xmb->textures.list[XMB_TEXTURE_MAIN_MENU]; + case MENU_ENUM_LABEL_UPDATE_CHEATS: + return xmb->textures.list[XMB_TEXTURE_CHEAT_OPTIONS]; + case MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST: + return xmb->textures.list[XMB_TEXTURE_IMAGE]; + case MENU_ENUM_LABEL_UPDATE_OVERLAYS: + case MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_OVERLAY]; + case MENU_ENUM_LABEL_UPDATE_CG_SHADERS: + case MENU_ENUM_LABEL_UPDATE_GLSL_SHADERS: + case MENU_ENUM_LABEL_UPDATE_SLANG_SHADERS: + return xmb->textures.list[XMB_TEXTURE_SHADER_OPTIONS]; + case MENU_ENUM_LABEL_INFORMATION: + case MENU_ENUM_LABEL_INFORMATION_LIST: + case MENU_ENUM_LABEL_SYSTEM_INFORMATION: + case MENU_ENUM_LABEL_UPDATE_CORE_INFO_FILES: + return xmb->textures.list[XMB_TEXTURE_INFO]; + case MENU_ENUM_LABEL_UPDATE_DATABASES: + case MENU_ENUM_LABEL_DATABASE_MANAGER_LIST: + return xmb->textures.list[XMB_TEXTURE_RDB]; + case MENU_ENUM_LABEL_CURSOR_MANAGER_LIST: + return xmb->textures.list[XMB_TEXTURE_CURSOR]; + case MENU_ENUM_LABEL_HELP_LIST: + case MENU_ENUM_LABEL_HELP_CONTROLS: + case MENU_ENUM_LABEL_HELP_LOADING_CONTENT: + case MENU_ENUM_LABEL_HELP_SCANNING_CONTENT: + case MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE: + case MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD: + case MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING: + return xmb->textures.list[XMB_TEXTURE_HELP]; + case MENU_ENUM_LABEL_QUIT_RETROARCH: + return xmb->textures.list[XMB_TEXTURE_EXIT]; + /* Settings icons*/ + case MENU_ENUM_LABEL_DRIVER_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_DRIVERS]; + case MENU_ENUM_LABEL_VIDEO_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_VIDEO]; + case MENU_ENUM_LABEL_AUDIO_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_AUDIO]; + case MENU_ENUM_LABEL_AUDIO_MIXER_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_MIXER]; + case MENU_ENUM_LABEL_INPUT_SETTINGS: + case MENU_ENUM_LABEL_UPDATE_AUTOCONFIG_PROFILES: + return xmb->textures.list[XMB_TEXTURE_INPUT]; + case MENU_ENUM_LABEL_LATENCY_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_LATENCY]; + case MENU_ENUM_LABEL_SAVING_SETTINGS: + case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE: + case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR: + case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME: + return xmb->textures.list[XMB_TEXTURE_SAVING]; + case MENU_ENUM_LABEL_LOGGING_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_LOG]; + case MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_FRAMESKIP]; + case MENU_ENUM_LABEL_RECORDING_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_RECORD]; + case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_OSD]; + case MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_UI]; + case MENU_ENUM_LABEL_POWER_MANAGEMENT_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_POWER]; + case MENU_ENUM_LABEL_RETRO_ACHIEVEMENTS_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_ACHIEVEMENTS]; + case MENU_ENUM_LABEL_NETWORK_INFORMATION: + case MENU_ENUM_LABEL_NETWORK_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_NETWORK]; + case MENU_ENUM_LABEL_PLAYLIST_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_PLAYLIST]; + case MENU_ENUM_LABEL_USER_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_USER]; + case MENU_ENUM_LABEL_DIRECTORY_SETTINGS: + case MENU_ENUM_LABEL_SCAN_DIRECTORY: + return xmb->textures.list[XMB_TEXTURE_FOLDER]; + case MENU_ENUM_LABEL_PRIVACY_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_PRIVACY]; + + case MENU_ENUM_LABEL_REWIND_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_REWIND]; + case MENU_ENUM_LABEL_QUICK_MENU_OVERRIDE_OPTIONS: + return xmb->textures.list[XMB_TEXTURE_OVERRIDE]; + case MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_NOTIFICATIONS]; +#ifdef HAVE_NETWORKING + case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: + return xmb->textures.list[XMB_TEXTURE_RUN]; + case MENU_ENUM_LABEL_NETPLAY_DISABLE_HOST: /* FIXME does not load */ + return xmb->textures.list[XMB_TEXTURE_CLOSE]; + case MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT: + return xmb->textures.list[XMB_TEXTURE_ROOM]; + case MENU_ENUM_LABEL_NETPLAY_REFRESH_ROOMS: + return xmb->textures.list[XMB_TEXTURE_IROOM]; + case MENU_ENUM_LABEL_NETPLAY_LAN_SCAN_SETTINGS: + return xmb->textures.list[XMB_TEXTURE_LANROOM]; +#endif + default: + break; + } + } + break; + } } switch(type) @@ -4346,6 +4511,10 @@ static const char *xmb_texture_path(unsigned id) return "netplay.png"; case XMB_TEXTURE_ROOM: return "room.png"; + case XMB_TEXTURE_LANROOM: + return "netplay - LAN Room.png"; + case XMB_TEXTURE_IROOM: + return "netplay - iRoom.png"; #if 0 /* stub these out until we have the icons */ case XMB_TEXTURE_ROOM_LAN: @@ -4360,7 +4529,60 @@ static const char *xmb_texture_path(unsigned id) return "key-hover.png"; case XMB_TEXTURE_DIALOG_SLICE: return "dialog-slice.png"; - + case XMB_TEXTURE_ACHIEVEMENTS: + return "menu_achievements.png"; + case XMB_TEXTURE_AUDIO: + return "menu_audio.png"; + case XMB_TEXTURE_DRIVERS: + return "menu_drivers.png"; + case XMB_TEXTURE_EXIT: + return "menu_exit.png"; + case XMB_TEXTURE_FRAMESKIP: + return "menu_frameskip.png"; + case XMB_TEXTURE_HELP: + return "menu_help.png"; + case XMB_TEXTURE_INFO: + return "menu_info.png"; + case XMB_TEXTURE_INPUT: + return "Libretro - Pad.png"; + case XMB_TEXTURE_LATENCY: + return "menu_latency.png"; + case XMB_TEXTURE_NETWORK: + return "menu_network.png"; + case XMB_TEXTURE_POWER: + return "menu_power.png"; + case XMB_TEXTURE_RECORD: + return "menu_record.png"; + case XMB_TEXTURE_SAVING: + return "menu_saving.png"; + case XMB_TEXTURE_UPDATER: + return "menu_updater.png"; + case XMB_TEXTURE_VIDEO: + return "menu_video.png"; + case XMB_TEXTURE_MIXER: + return "menu_mixer.png"; + case XMB_TEXTURE_LOG: + return "menu_log.png"; + case XMB_TEXTURE_OSD: + return "menu_osd.png"; + case XMB_TEXTURE_UI: + return "menu_ui.png"; + case XMB_TEXTURE_USER: + return "menu_user.png"; + case XMB_TEXTURE_PRIVACY: + return "menu_privacy.png"; + case XMB_TEXTURE_PLAYLIST: + return "menu_playlist.png"; + case XMB_TEXTURE_QUICKMENU: + return "menu_quickmenu.png"; + case XMB_TEXTURE_REWIND: + return "menu_rewind.png"; + case XMB_TEXTURE_OVERLAY: + return "menu_overlay.png"; + case XMB_TEXTURE_OVERRIDE: + return "menu_override.png"; + case XMB_TEXTURE_NOTIFICATIONS: + return "menu_notifications.png"; } return NULL; From ae562614c45148c43f64c346cd6f7cf55dd8012b Mon Sep 17 00:00:00 2001 From: alfrix Date: Mon, 13 Aug 2018 18:42:46 -0300 Subject: [PATCH 006/182] Add dot-art to the supported list in the new XMB icons --- menu/drivers/xmb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index d01bdb9337..9d2b463a9c 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2239,7 +2239,6 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_SAVE_STATE: return xmb->textures.list[XMB_TEXTURE_SAVESTATE]; case MENU_ENUM_LABEL_LOAD_STATE: - case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET: return xmb->textures.list[XMB_TEXTURE_LOADSTATE]; case MENU_ENUM_LABEL_PARENT_DIRECTORY: case MENU_ENUM_LABEL_UNDO_LOAD_STATE: @@ -2280,7 +2279,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, settings_t *settings = config_get_ptr(); if (settings->uints.menu_xmb_theme == XMB_ICON_THEME_MONOCHROME || settings->uints.menu_xmb_theme == XMB_ICON_THEME_MONOCHROME_INVERTED || - settings->uints.menu_xmb_theme == XMB_ICON_THEME_CUSTOM + settings->uints.menu_xmb_theme == XMB_ICON_THEME_CUSTOM || + settings->uints.menu_xmb_theme == XMB_ICON_THEME_DOTART ) { switch (enum_idx) From b35914fcc02522045dd7bd2ad1025601cd59fd21 Mon Sep 17 00:00:00 2001 From: alfrix Date: Mon, 13 Aug 2018 19:41:18 -0300 Subject: [PATCH 007/182] Fix Stop Netplay Host --- menu/drivers/xmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 9d2b463a9c..6584de207f 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2387,7 +2387,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, #ifdef HAVE_NETWORKING case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: return xmb->textures.list[XMB_TEXTURE_RUN]; - case MENU_ENUM_LABEL_NETPLAY_DISABLE_HOST: /* FIXME does not load */ + case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: return xmb->textures.list[XMB_TEXTURE_CLOSE]; case MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT: return xmb->textures.list[XMB_TEXTURE_ROOM]; From 4a9ef99759fe841b71304adaed4f8c0ac25325d5 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 14 Aug 2018 16:04:03 -0400 Subject: [PATCH 008/182] Qt: fix core loading after 73f2710 --- ui/drivers/qt/ui_qt_load_core_window.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui/drivers/qt/ui_qt_load_core_window.cpp b/ui/drivers/qt/ui_qt_load_core_window.cpp index 00f29f38de..8179b82570 100644 --- a/ui/drivers/qt/ui_qt_load_core_window.cpp +++ b/ui/drivers/qt/ui_qt_load_core_window.cpp @@ -124,6 +124,11 @@ void LoadCoreWindow::loadCore(const char *path) /* const-removing cast is safe here because the path is never written to */ rarch_ctl(RARCH_CTL_SET_LIBRETRO_PATH, const_cast(path)); + command_event(CMD_EVENT_CORE_INFO_DEINIT, NULL); + command_event(CMD_EVENT_CORE_INFO_INIT, NULL); + + core_info_init_current_core(); + if (!command_event(CMD_EVENT_LOAD_CORE, NULL)) { QMessageBox::critical(this, msg_hash_to_str(MSG_ERROR), msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE)); From 572c1ea2d309ede4e0b754db520a43a1dcfc7ef5 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 14 Aug 2018 00:47:10 -0400 Subject: [PATCH 009/182] Qt: initial shader parameter support --- intl/msg_hash_ja.h | 2 + intl/msg_hash_us.h | 2 + msg_hash.h | 1 + ui/drivers/qt/ui_qt_window.cpp | 243 +++++++++++++++++++++++++++++++++ ui/drivers/ui_qt.cpp | 2 + ui/drivers/ui_qt.h | 8 ++ 6 files changed, 258 insertions(+) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 6612b1adba..73b6cf9f35 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3500,6 +3500,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW, "表示(&V)") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_CLOSED_DOCKS, "閉じたドック") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_SHADER_PARAMS, + "シェーダーのパラメータ") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS, "設定(&O)...") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 3eb0d97ea1..0590f8d60d 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3756,6 +3756,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW, "&View") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_CLOSED_DOCKS, "Closed Docks") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_SHADER_PARAMS, + "Shader Parameters") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS, "&Options...") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS, diff --git a/msg_hash.h b/msg_hash.h index 8c75461637..1a6f5c78f0 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1886,6 +1886,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW, MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_CLOSED_DOCKS, + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_SHADER_PARAMS, MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS, MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS, MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY, diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index d8c8d40ad3..5ef4ed8e18 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include "../ui_qt.h" #include "ui_qt_load_core_window.h" @@ -927,6 +928,7 @@ MainWindow::MainWindow(QWidget *parent) : ,m_allPlaylistsGridMaxCount(0) ,m_playlistEntryDialog(NULL) ,m_statusMessageElapsedTimer() + ,m_shaderParamsDialog(NULL) ,m_networkManager(new QNetworkAccessManager(this)) ,m_updateProgressDialog(new QProgressDialog()) ,m_updateFile() @@ -1214,6 +1216,247 @@ void MainWindow::removeUpdateTempFiles() } } +void MainWindow::onShaderParamsClicked() +{ + QFormLayout *form = new QFormLayout(); + video_shader_ctx_t shader_info; + unsigned i; + + video_shader_driver_get_current_shader(&shader_info); + + if (!shader_info.data || shader_info.data->num_parameters > GFX_MAX_PARAMETERS) + return; + + /* shader might have changed, so re-create the entire window */ + if (m_shaderParamsDialog) + delete m_shaderParamsDialog; + + m_shaderParamsDialog = new QDialog(); + m_shaderParamsDialog->setLayout(form); + m_shaderParamsDialog->setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS)); + + for (i = 0; i < shader_info.data->num_parameters; i++) + { + struct video_shader_parameter *param = &shader_info.data->parameters[i]; + QString desc = param->desc; + + if ((param->minimum == 0.0) + && (param->maximum + == (param->minimum + + param->step))) + { + /* option is basically a bool, so use a checkbox */ + QCheckBox *checkBox = new QCheckBox(m_shaderParamsDialog); + checkBox->setChecked(param->current == param->maximum ? true : false); + checkBox->setProperty("param", QVariant::fromValue(param)); + + connect(checkBox, SIGNAL(clicked()), this, SLOT(onShaderParamCheckBoxClicked())); + + form->addRow(desc, checkBox); + } + else + { + QDoubleSpinBox *doubleSpinBox = NULL; + QSpinBox *spinBox = NULL; + QHBoxLayout *box = new QHBoxLayout(); + QSlider *slider = new QSlider(Qt::Horizontal, m_shaderParamsDialog); + double value = lerp(param->minimum, param->maximum, 0, 100, param->current); + double intpart = 0; + bool stepIsFractional = modf(param->step, &intpart); + + slider->setRange(0, 100); + slider->setSingleStep(1); + slider->setValue(value); + slider->setProperty("param", QVariant::fromValue(param)); + + connect(slider, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSliderValueChanged(int))); + + box->addWidget(slider); + + if (stepIsFractional) + { + doubleSpinBox = new QDoubleSpinBox(m_shaderParamsDialog); + doubleSpinBox->setRange(param->minimum, param->maximum); + doubleSpinBox->setSingleStep(param->step); + doubleSpinBox->setValue(param->current); + doubleSpinBox->setProperty("slider", QVariant::fromValue(slider)); + slider->setProperty("doubleSpinBox", QVariant::fromValue(doubleSpinBox)); + + connect(doubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onShaderParamDoubleSpinBoxValueChanged(double))); + + box->addWidget(doubleSpinBox); + } + else + { + spinBox = new QSpinBox(m_shaderParamsDialog); + spinBox->setRange(param->minimum, param->maximum); + spinBox->setSingleStep(param->step); + spinBox->setValue(param->current); + spinBox->setProperty("slider", QVariant::fromValue(slider)); + slider->setProperty("spinBox", QVariant::fromValue(spinBox)); + + connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSpinBoxValueChanged(int))); + + box->addWidget(spinBox); + } + + form->addRow(desc, box); + } + } + + m_shaderParamsDialog->resize(720, 480); + m_shaderParamsDialog->show(); +} + +void MainWindow::onShaderParamCheckBoxClicked() +{ + QCheckBox *checkBox = qobject_cast(sender()); + QVariant paramVariant; + struct video_shader_parameter *param = NULL; + + if (!checkBox) + return; + + paramVariant = checkBox->property("param"); + + if (paramVariant.isValid()) + { + param = paramVariant.value(); + + if (param) + param->current = (checkBox->isChecked() ? param->maximum : param->minimum); + } +} + +void MainWindow::onShaderParamSliderValueChanged(int value) +{ + QVariant spinBoxVariant; + QVariant paramVariant; + QSlider *slider = qobject_cast(sender()); + struct video_shader_parameter *param = NULL; + double newValue = 0.0; + + if (!slider) + return; + + spinBoxVariant = slider->property("spinBox"); + + if (spinBoxVariant.isValid()) + { + QSpinBox *spinBox = spinBoxVariant.value(); + + if (!spinBox) + return; + + spinBox->blockSignals(true); + spinBox->setValue(slider->value()); + spinBox->blockSignals(false); + } + else + { + QVariant doubleSpinBoxVariant = slider->property("doubleSpinBox"); + QDoubleSpinBox *doubleSpinBox = doubleSpinBoxVariant.value(); + + if (!doubleSpinBox) + return; + + doubleSpinBox->blockSignals(true); + doubleSpinBox->setValue(slider->value()); + doubleSpinBox->blockSignals(false); + } + + paramVariant = slider->property("param"); + + if (paramVariant.isValid()) + { + param = paramVariant.value(); + + if (param) + { + newValue = lerp(0, 100, param->minimum, param->maximum, slider->value()); + param->current = newValue; + } + } +} + +void MainWindow::onShaderParamSpinBoxValueChanged(int value) +{ + QSpinBox *spinBox = qobject_cast(sender()); + QVariant sliderVariant; + QVariant paramVariant; + QSlider *slider = NULL; + struct video_shader_parameter *param = NULL; + double newValue = 0.0; + + if (!spinBox) + return; + + sliderVariant = spinBox->property("slider"); + + if (!sliderVariant.isValid()) + return; + + slider = sliderVariant.value(); + + if (!slider) + return; + + paramVariant = slider->property("param"); + + if (paramVariant.isValid()) + { + param = paramVariant.value(); + + if (param) + { + param->current = value; + newValue = lerp(param->minimum, param->maximum, 0, 100, param->current); + slider->blockSignals(true); + slider->setValue(newValue); + slider->blockSignals(false); + } + } +} + +void MainWindow::onShaderParamDoubleSpinBoxValueChanged(double value) +{ + QDoubleSpinBox *doubleSpinBox = qobject_cast(sender()); + QVariant sliderVariant; + QVariant paramVariant; + QSlider *slider = NULL; + struct video_shader_parameter *param = NULL; + double newValue = 0.0; + + if (!doubleSpinBox) + return; + + sliderVariant = doubleSpinBox->property("slider"); + + if (!sliderVariant.isValid()) + return; + + slider = sliderVariant.value(); + + if (!slider) + return; + + paramVariant = slider->property("param"); + + if (paramVariant.isValid()) + { + param = paramVariant.value(); + + if (param) + { + param->current = value; + newValue = lerp(param->minimum, param->maximum, 0, 100, param->current); + slider->blockSignals(true); + slider->setValue(newValue); + slider->blockSignals(false); + } + } +} + void MainWindow::onPlaylistFilesDropped(QStringList files) { addFilesToPlaylist(files); diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index 690635a4aa..7fcace03e0 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -321,6 +321,8 @@ static void* ui_companion_qt_init(void) QObject::connect(viewClosedDocksMenu, SIGNAL(aboutToShow()), mainwindow, SLOT(onViewClosedDocksAboutToShow())); + viewMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_SHADER_PARAMS), mainwindow, SLOT(onShaderParamsClicked())); + viewMenu->addSeparator(); viewMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_ICONS), mainwindow, SLOT(onIconViewClicked())); viewMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_LIST), mainwindow, SLOT(onListViewClicked())); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 628ae62d31..50943d2a6c 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -42,6 +42,7 @@ extern "C" { #include #include #include "../ui_companion_driver.h" +#include "../../gfx/video_driver.h" } class QApplication; @@ -433,6 +434,7 @@ private slots: void onGridItemDoubleClicked(); void onGridItemClicked(ThumbnailWidget *thumbnailWidget = NULL); void onPlaylistFilesDropped(QStringList files); + void onShaderParamsClicked(); void onUpdateNetworkError(QNetworkReply::NetworkError code); void onUpdateNetworkSslErrors(const QList &errors); void onRetroArchUpdateDownloadFinished(); @@ -441,6 +443,10 @@ private slots: void onUpdateDownloadCanceled(); void onShowErrorMessage(QString msg); void onContributorsClicked(); + void onShaderParamCheckBoxClicked(); + void onShaderParamSliderValueChanged(int value); + void onShaderParamSpinBoxValueChanged(int value); + void onShaderParamDoubleSpinBoxValueChanged(double value); int onExtractArchive(QString path); private: @@ -514,6 +520,7 @@ private: int m_allPlaylistsGridMaxCount; PlaylistEntryDialog *m_playlistEntryDialog; QElapsedTimer m_statusMessageElapsedTimer; + QDialog *m_shaderParamsDialog; QNetworkAccessManager *m_networkManager; QProgressDialog *m_updateProgressDialog; QFile m_updateFile; @@ -526,6 +533,7 @@ protected: Q_DECLARE_METATYPE(ThumbnailWidget) Q_DECLARE_METATYPE(QPointer) +Q_DECLARE_METATYPE(struct video_shader_parameter*) RETRO_BEGIN_DECLS From 6de438435054635220f82e2fd2cec1c4c8536f9e Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 14 Aug 2018 18:42:23 -0400 Subject: [PATCH 010/182] glsl: don't clear the shader source --- gfx/drivers_shader/shader_glsl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gfx/drivers_shader/shader_glsl.c b/gfx/drivers_shader/shader_glsl.c index 8d8dbb4590..784cf41c7f 100644 --- a/gfx/drivers_shader/shader_glsl.c +++ b/gfx/drivers_shader/shader_glsl.c @@ -539,8 +539,6 @@ static bool gl_glsl_compile_programs( return false; } - *pass->source.path = '\0'; - vertex = pass->source.string.vertex; fragment = pass->source.string.fragment; From 4a86d298105542e540b55c8b7ecf05c7077ccdeb Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 14 Aug 2018 18:44:19 -0400 Subject: [PATCH 011/182] shaders: fix memory leak --- gfx/video_shader_parse.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index 00d96ece1d..36d0460180 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -155,6 +155,7 @@ static bool video_shader_parse_pass(config_file_t *conf, strlcpy(pass->source.path, tmp_str, sizeof(pass->source.path)); else strlcpy(pass->source.path, tmp_path, sizeof(pass->source.path)); + free(tmp_path); /* Smooth */ @@ -208,7 +209,10 @@ static bool video_shader_parse_pass(config_file_t *conf, config_get_array(conf, scale_name_buf, scale_type_y, sizeof(scale_type_y)); if (!*scale_type && !*scale_type_x && !*scale_type_y) + { + free(tmp_str); return true; + } if (*scale_type) { @@ -253,6 +257,7 @@ static bool video_shader_parse_pass(config_file_t *conf, } snprintf(attr_name_buf, sizeof(attr_name_buf), "scale%u", i); + if (scale->type_x == RARCH_SCALE_ABSOLUTE) { if (config_get_int(conf, attr_name_buf, &iattr)) @@ -277,6 +282,7 @@ static bool video_shader_parse_pass(config_file_t *conf, } snprintf(attr_name_buf, sizeof(attr_name_buf), "scale%u", i); + if (scale->type_y == RARCH_SCALE_ABSOLUTE) { if (config_get_int(conf, attr_name_buf, &iattr)) @@ -500,9 +506,9 @@ bool video_shader_resolve_parameters(config_file_t *conf, continue; #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) - /* First try to use the more robust slang + /* First try to use the more robust slang * implementation to support #includes. */ - /* FIXME: The check for slang can be removed + /* FIXME: The check for slang can be removed * if it's sufficiently tested for * GLSL/Cg as well, it should be the same implementation. */ if (string_is_equal(path_get_extension(path), "slang") && @@ -632,7 +638,7 @@ static bool video_shader_parse_imports(config_file_t *conf, var->type = RARCH_STATE_TRANSITION_PREV; else if (string_is_equal(semantic, "python")) var->type = RARCH_STATE_PYTHON; - else + else { RARCH_ERR("Invalid semantic.\n"); goto error; @@ -752,11 +758,14 @@ bool video_shader_read_conf_cgp(config_file_t *conf, if (!video_shader_parse_pass(conf, &shader->pass[i], i)) { if (file_list) + { string_list_free(file_list); + file_list = NULL; + } return false; } - if (settings->bools.video_shader_watch_files) + if (settings->bools.video_shader_watch_files && file_list) string_list_append(file_list, shader->pass[i].source.path, attr); } @@ -770,7 +779,8 @@ bool video_shader_read_conf_cgp(config_file_t *conf, frontend_driver_watch_path_for_changes(file_list, flags, &file_change_data); - string_list_free(file_list); + if (file_list) + string_list_free(file_list); } if (!video_shader_parse_textures(conf, shader)) @@ -1130,7 +1140,7 @@ enum rarch_shader_type video_shader_get_type_from_ext( case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: { - struct retro_hw_render_callback *hwr = + struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); if (hwr) { @@ -1162,7 +1172,7 @@ enum rarch_shader_type video_shader_get_type_from_ext( case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: { - struct retro_hw_render_callback *hwr = + struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); if (hwr) { @@ -1227,7 +1237,7 @@ enum rarch_shader_type video_shader_get_type_from_ext( } } if ( - string_is_equal_case_insensitive(ext, "slangp") + string_is_equal_case_insensitive(ext, "slangp") ) { *is_preset = true; From 560149857b78d56094efeb8fb6f9363e2fb8ccce Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 14 Aug 2018 18:46:32 -0400 Subject: [PATCH 012/182] shaders: track the pass for each parameter --- gfx/video_shader_parse.c | 6 ++++-- gfx/video_shader_parse.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index 36d0460180..001f8ba055 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -545,9 +545,11 @@ bool video_shader_resolve_parameters(config_file_t *conf, if (ret == 5) param->step = 0.1f * (param->maximum - param->minimum); - RARCH_LOG("Found #pragma parameter %s (%s) %f %f %f %f\n", + param->pass = i; + + RARCH_LOG("Found #pragma parameter %s (%s) %f %f %f %f in pass %d\n", param->desc, param->id, param->initial, - param->minimum, param->maximum, param->step); + param->minimum, param->maximum, param->step, param->pass); param->current = param->initial; shader->num_parameters++; diff --git a/gfx/video_shader_parse.h b/gfx/video_shader_parse.h index cb76a23a85..744c7c9ab2 100644 --- a/gfx/video_shader_parse.h +++ b/gfx/video_shader_parse.h @@ -105,6 +105,7 @@ struct video_shader_parameter float initial; float maximum; float step; + int pass; }; struct video_shader_pass From 553394c266322e19c17f2a59785eb9b55ccb109e Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 14 Aug 2018 21:38:45 -0400 Subject: [PATCH 013/182] Qt: fix setting of spinbox values when modifying shader parameter sliders --- ui/drivers/qt/ui_qt_window.cpp | 49 +++++++++++++++++----------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 5ef4ed8e18..0cd1a7b4ce 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -1340,31 +1340,6 @@ void MainWindow::onShaderParamSliderValueChanged(int value) return; spinBoxVariant = slider->property("spinBox"); - - if (spinBoxVariant.isValid()) - { - QSpinBox *spinBox = spinBoxVariant.value(); - - if (!spinBox) - return; - - spinBox->blockSignals(true); - spinBox->setValue(slider->value()); - spinBox->blockSignals(false); - } - else - { - QVariant doubleSpinBoxVariant = slider->property("doubleSpinBox"); - QDoubleSpinBox *doubleSpinBox = doubleSpinBoxVariant.value(); - - if (!doubleSpinBox) - return; - - doubleSpinBox->blockSignals(true); - doubleSpinBox->setValue(slider->value()); - doubleSpinBox->blockSignals(false); - } - paramVariant = slider->property("param"); if (paramVariant.isValid()) @@ -1377,6 +1352,30 @@ void MainWindow::onShaderParamSliderValueChanged(int value) param->current = newValue; } } + + if (spinBoxVariant.isValid()) + { + QSpinBox *spinBox = spinBoxVariant.value(); + + if (!spinBox) + return; + + spinBox->blockSignals(true); + spinBox->setValue(newValue); + spinBox->blockSignals(false); + } + else + { + QVariant doubleSpinBoxVariant = slider->property("doubleSpinBox"); + QDoubleSpinBox *doubleSpinBox = doubleSpinBoxVariant.value(); + + if (!doubleSpinBox) + return; + + doubleSpinBox->blockSignals(true); + doubleSpinBox->setValue(newValue); + doubleSpinBox->blockSignals(false); + } } void MainWindow::onShaderParamSpinBoxValueChanged(int value) From 341cf633997ee2c7827d2d0f144ce1f29171dbcb Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 14 Aug 2018 21:38:52 -0400 Subject: [PATCH 014/182] Qt: show shader pass in parameters window, reload shader params when shader is reloaded --- command.c | 8 +- command.h | 2 + gfx/video_driver.c | 45 +++++---- gfx/video_shader_parse.c | 3 + griffin/griffin_cpp.cpp | 1 + ui/drivers/qt/ui_qt_window.cpp | 180 ++++++++++++++++++++++----------- ui/drivers/ui_qt.cpp | 16 ++- ui/drivers/ui_qt.h | 17 +++- ui/ui_companion_driver.c | 4 + 9 files changed, 192 insertions(+), 84 deletions(-) diff --git a/command.c b/command.c index 18ca322b53..4ccc4f5f6f 100644 --- a/command.c +++ b/command.c @@ -1336,8 +1336,8 @@ static void command_event_restore_default_shader_preset(void) static void command_event_restore_remaps(void) { - if (rarch_ctl(RARCH_CTL_IS_REMAPS_CORE_ACTIVE, NULL) || - rarch_ctl(RARCH_CTL_IS_REMAPS_CONTENT_DIR_ACTIVE, NULL) || + if (rarch_ctl(RARCH_CTL_IS_REMAPS_CORE_ACTIVE, NULL) || + rarch_ctl(RARCH_CTL_IS_REMAPS_CONTENT_DIR_ACTIVE, NULL) || rarch_ctl(RARCH_CTL_IS_REMAPS_GAME_ACTIVE, NULL)) input_remapping_set_defaults(true); } @@ -2441,10 +2441,14 @@ TODO: Add a setting for these tweaks */ if (!command_event_save_core_config()) return false; break; + case CMD_EVENT_SHADER_PRESET_LOADED: + ui_companion_event_command(cmd); + break; case CMD_EVENT_SHADERS_APPLY_CHANGES: #ifdef HAVE_MENU menu_shader_manager_apply_changes(); #endif + ui_companion_event_command(cmd); break; case CMD_EVENT_PAUSE_CHECKS: { diff --git a/command.h b/command.h index 6b50d6f3eb..1a7e84fac7 100644 --- a/command.h +++ b/command.h @@ -158,6 +158,8 @@ enum event_command CMD_EVENT_MENU_REFRESH, /* Applies shader changes. */ CMD_EVENT_SHADERS_APPLY_CHANGES, + /* A new shader preset has been loaded */ + CMD_EVENT_SHADER_PRESET_LOADED, /* Initializes shader directory. */ CMD_EVENT_SHADER_DIR_INIT, /* Deinitializes shader directory. */ diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 3a38c46eed..3fa843eefa 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -1641,7 +1641,7 @@ bool video_driver_is_stub_frame(void) bool video_driver_supports_recording(void) { settings_t *settings = config_get_ptr(); - return settings->bools.video_gpu_record + return settings->bools.video_gpu_record && current_video->read_viewport; } @@ -1668,7 +1668,7 @@ void video_driver_set_viewport_config(void) { struct retro_game_geometry *geom = &video_driver_av_info.geometry; - if (geom->aspect_ratio > 0.0f && + if (geom->aspect_ratio > 0.0f && settings->bools.video_aspect_ratio_auto) aspectratio_lut[ASPECT_RATIO_CONFIG].value = geom->aspect_ratio; else @@ -1898,7 +1898,7 @@ void video_driver_update_viewport(struct video_viewport* vp, bool force_full, bo } else if (device_aspect > desired_aspect) { - delta = (desired_aspect / device_aspect - 1.0f) + delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f; vp->x = (int)roundf(vp->full_width * (0.5f - delta)); vp->width = (unsigned)roundf(2.0f * vp->full_width * delta); @@ -1909,7 +1909,7 @@ void video_driver_update_viewport(struct video_viewport* vp, bool force_full, bo { vp->x = 0; vp->width = vp->full_width; - delta = (device_aspect / desired_aspect - 1.0f) + delta = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f; vp->y = (int)roundf(vp->full_height * (0.5f - delta)); vp->height = (unsigned)roundf(2.0f * vp->full_height * delta); @@ -2324,7 +2324,7 @@ void video_viewport_get_scaled_integer(struct video_viewport *vp, unsigned base_width; /* Use system reported sizes as these define the * geometry for the "normal" case. */ - unsigned base_height = + unsigned base_height = video_driver_av_info.geometry.base_height; if (base_height == 0) @@ -2631,9 +2631,9 @@ void video_driver_frame(const void *data, unsigned width, /* Display the FPS, with a higher priority. */ if (video_info.fps_show) runloop_msg_queue_push(video_info.fps_text, 2, 1, true); - - /* trigger set resolution*/ - if (video_info.crt_switch_resolution) + + /* trigger set resolution*/ + if (video_info.crt_switch_resolution) { video_driver_crt_switching_active = true; @@ -2646,9 +2646,9 @@ void video_driver_frame(const void *data, unsigned width, crt_switch_res_core(width, height, video_driver_core_hz); } else if (!video_info.crt_switch_resolution) - video_driver_crt_switching_active = false; - - /* trigger set resolution*/ + video_driver_crt_switching_active = false; + + /* trigger set resolution*/ } void video_driver_display_type_set(enum rarch_display_type type) @@ -2741,8 +2741,8 @@ void video_driver_build_info(video_frame_info_t *video_info) settings = config_get_ptr(); custom_vp = &settings->video_viewport_custom; video_info->refresh_rate = settings->floats.video_refresh_rate; - video_info->crt_switch_resolution = settings->bools.crt_switch_resolution; - video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super; + video_info->crt_switch_resolution = settings->bools.crt_switch_resolution; + video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super; video_info->black_frame_insertion = settings->bools.video_black_frame_insertion; video_info->hard_sync = settings->bools.video_hard_sync; video_info->hard_sync_frames = settings->uints.video_hard_sync_frames; @@ -2873,13 +2873,13 @@ bool video_driver_translate_coord_viewport( return false; if (mouse_x >= 0 && mouse_x <= norm_full_vp_width) - scaled_screen_x = ((2 * mouse_x * 0x7fff) + scaled_screen_x = ((2 * mouse_x * 0x7fff) / norm_full_vp_width) - 0x7fff; else scaled_screen_x = -0x8000; /* OOB */ if (mouse_y >= 0 && mouse_y <= norm_full_vp_height) - scaled_screen_y = ((2 * mouse_y * 0x7fff) + scaled_screen_y = ((2 * mouse_y * 0x7fff) / norm_full_vp_height) - 0x7fff; else scaled_screen_y = -0x8000; /* OOB */ @@ -2888,13 +2888,13 @@ bool video_driver_translate_coord_viewport( mouse_y -= vp->y; if (mouse_x >= 0 && mouse_x <= norm_vp_width) - scaled_x = ((2 * mouse_x * 0x7fff) + scaled_x = ((2 * mouse_x * 0x7fff) / norm_vp_width) - 0x7fff; else scaled_x = -0x8000; /* OOB */ if (mouse_y >= 0 && mouse_y <= norm_vp_height) - scaled_y = ((2 * mouse_y * 0x7fff) + scaled_y = ((2 * mouse_y * 0x7fff) / norm_vp_height) - 0x7fff; else scaled_y = -0x8000; /* OOB */ @@ -2920,7 +2920,7 @@ void video_driver_get_status(uint64_t *frame_count, bool * is_alive, bool *is_focused) { *frame_count = video_driver_frame_count; - *is_alive = current_video ? + *is_alive = current_video ? current_video->alive(video_driver_data) : true; *is_focused = video_driver_cb_has_focus(); } @@ -3002,7 +3002,7 @@ bool video_context_driver_find_next_driver(void) * * Initialize graphics context driver. * - * Returns: graphics context driver if successfully initialized, + * Returns: graphics context driver if successfully initialized, * otherwise NULL. **/ static const gfx_ctx_driver_t *video_context_driver_init( @@ -3238,7 +3238,7 @@ bool video_context_driver_get_refresh_rate(float *refresh_rate) return false; if (refresh_rate) - *refresh_rate = + *refresh_rate = current_video_context.get_refresh_rate(video_context_data); return true; @@ -3247,7 +3247,7 @@ bool video_context_driver_get_refresh_rate(float *refresh_rate) bool video_context_driver_input_driver(gfx_ctx_input_t *inp) { settings_t *settings = config_get_ptr(); - const char *joypad_name = settings ? + const char *joypad_name = settings ? settings->arrays.input_joypad_driver : NULL; if (!current_video_context.input_driver) @@ -3518,6 +3518,9 @@ bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader) bool video_shader_driver_direct_get_current_shader( video_shader_ctx_t *shader) { + if (!current_shader) + return false; + shader->data = current_shader->get_current_shader(current_shader_data); return true; diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index 001f8ba055..005a9d64fb 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -35,6 +35,7 @@ #include "../verbosity.h" #include "../configuration.h" #include "../frontend/frontend_driver.h" +#include "../command.h" #include "video_driver.h" #include "video_shader_parse.h" @@ -785,6 +786,8 @@ bool video_shader_read_conf_cgp(config_file_t *conf, string_list_free(file_list); } + command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL); + if (!video_shader_parse_textures(conf, shader)) return false; diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index 970ac5cffe..17aae41d3d 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -41,6 +41,7 @@ UI #include "../ui/drivers/qt/ui_qt_browser_window.cpp" #include "../ui/drivers/qt/ui_qt_msg_window.cpp" #include "../ui/drivers/qt/ui_qt_application.cpp" +#include "../ui/drivers/qt/flowlayout.cpp" #endif /*============================================================ diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 0cd1a7b4ce..6c2b63156a 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -203,6 +203,22 @@ static void setElidedText(QLabel *label, QWidget *clipWidget, int padding, const const QPixmap getInvader(); +ShaderParamsDialog::ShaderParamsDialog(QWidget *parent) : + QDialog(parent) +{ +} + +ShaderParamsDialog::~ShaderParamsDialog() +{ +} + +void ShaderParamsDialog::closeEvent(QCloseEvent *event) +{ + QDialog::closeEvent(event); + + emit closed(); +} + GridItem::GridItem() : QObject() ,widget(NULL) @@ -928,7 +944,7 @@ MainWindow::MainWindow(QWidget *parent) : ,m_allPlaylistsGridMaxCount(0) ,m_playlistEntryDialog(NULL) ,m_statusMessageElapsedTimer() - ,m_shaderParamsDialog(NULL) + ,m_shaderParamsDialog() ,m_networkManager(new QNetworkAccessManager(this)) ,m_updateProgressDialog(new QProgressDialog()) ,m_updateFile() @@ -1152,7 +1168,10 @@ MainWindow::MainWindow(QWidget *parent) : /* make sure these use an auto connection so it will be queued if called from a different thread (some facilities in RA log messages from other threads) */ connect(this, SIGNAL(gotLogMessage(const QString&)), this, SLOT(onGotLogMessage(const QString&)), Qt::AutoConnection); connect(this, SIGNAL(gotStatusMessage(QString,unsigned,unsigned,bool)), this, SLOT(onGotStatusMessage(QString,unsigned,unsigned,bool)), Qt::AutoConnection); - connect(this, SIGNAL(gotReloadPlaylists()), this, SLOT(onGotReloadPlaylists())); + connect(this, SIGNAL(gotReloadPlaylists()), this, SLOT(onGotReloadPlaylists()), Qt::AutoConnection); + connect(this, SIGNAL(gotReloadShaderParams()), this, SLOT(onGotReloadShaderParams()), Qt::AutoConnection); + + /* these are always queued */ connect(this, SIGNAL(showErrorMessageDeferred(QString)), this, SLOT(onShowErrorMessage(QString)), Qt::QueuedConnection); connect(this, SIGNAL(extractArchiveDeferred(QString)), this, SLOT(onExtractArchive(QString)), Qt::QueuedConnection); @@ -1218,9 +1237,11 @@ void MainWindow::removeUpdateTempFiles() void MainWindow::onShaderParamsClicked() { - QFormLayout *form = new QFormLayout(); video_shader_ctx_t shader_info; unsigned i; + int last_pass = -1; + QFormLayout *last_form = NULL; + QGroupBox *last_group = NULL; video_shader_driver_get_current_shader(&shader_info); @@ -1231,77 +1252,109 @@ void MainWindow::onShaderParamsClicked() if (m_shaderParamsDialog) delete m_shaderParamsDialog; - m_shaderParamsDialog = new QDialog(); - m_shaderParamsDialog->setLayout(form); + m_shaderParamsDialog = new ShaderParamsDialog(); + m_shaderParamsDialog->setLayout(new QVBoxLayout()); m_shaderParamsDialog->setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS)); - for (i = 0; i < shader_info.data->num_parameters; i++) + connect(m_shaderParamsDialog, SIGNAL(closed()), m_shaderParamsDialog, SLOT(deleteLater())); + + if (shader_info.data->num_parameters == 0) { - struct video_shader_parameter *param = &shader_info.data->parameters[i]; - QString desc = param->desc; + QLabel *label = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS), m_shaderParamsDialog); + label->setAlignment(Qt::AlignCenter); - if ((param->minimum == 0.0) - && (param->maximum - == (param->minimum - + param->step))) + m_shaderParamsDialog->layout()->addWidget(label); + } + else + { + /* NOTE: We assume that parameters are always grouped in order by the pass number, e.g., all parameters for pass 0 come first, then params for pass 1, etc. */ + for (i = 0; i < shader_info.data->num_parameters; i++) { - /* option is basically a bool, so use a checkbox */ - QCheckBox *checkBox = new QCheckBox(m_shaderParamsDialog); - checkBox->setChecked(param->current == param->maximum ? true : false); - checkBox->setProperty("param", QVariant::fromValue(param)); + struct video_shader_parameter *param = &shader_info.data->parameters[i]; + QString desc = param->desc; + QFormLayout *form = last_form; - connect(checkBox, SIGNAL(clicked()), this, SLOT(onShaderParamCheckBoxClicked())); - - form->addRow(desc, checkBox); - } - else - { - QDoubleSpinBox *doubleSpinBox = NULL; - QSpinBox *spinBox = NULL; - QHBoxLayout *box = new QHBoxLayout(); - QSlider *slider = new QSlider(Qt::Horizontal, m_shaderParamsDialog); - double value = lerp(param->minimum, param->maximum, 0, 100, param->current); - double intpart = 0; - bool stepIsFractional = modf(param->step, &intpart); - - slider->setRange(0, 100); - slider->setSingleStep(1); - slider->setValue(value); - slider->setProperty("param", QVariant::fromValue(param)); - - connect(slider, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSliderValueChanged(int))); - - box->addWidget(slider); - - if (stepIsFractional) + if (param->pass > last_pass) { - doubleSpinBox = new QDoubleSpinBox(m_shaderParamsDialog); - doubleSpinBox->setRange(param->minimum, param->maximum); - doubleSpinBox->setSingleStep(param->step); - doubleSpinBox->setValue(param->current); - doubleSpinBox->setProperty("slider", QVariant::fromValue(slider)); - slider->setProperty("doubleSpinBox", QVariant::fromValue(doubleSpinBox)); + QGroupBox *groupBox = NULL; + QFileInfo fileInfo(shader_info.data->pass[param->pass].source.path); + QString shaderBasename = fileInfo.completeBaseName(); - connect(doubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onShaderParamDoubleSpinBoxValueChanged(double))); + form = new QFormLayout(); + groupBox = new QGroupBox(shaderBasename); + groupBox->setLayout(form); - box->addWidget(doubleSpinBox); + m_shaderParamsDialog->layout()->addWidget(groupBox); + + last_form = form; + last_pass = param->pass; + } + + if ((param->minimum == 0.0) + && (param->maximum + == (param->minimum + + param->step))) + { + /* option is basically a bool, so use a checkbox */ + QCheckBox *checkBox = new QCheckBox(m_shaderParamsDialog); + checkBox->setChecked(param->current == param->maximum ? true : false); + checkBox->setProperty("param", QVariant::fromValue(param)); + + connect(checkBox, SIGNAL(clicked()), this, SLOT(onShaderParamCheckBoxClicked())); + + form->addRow(desc, checkBox); } else { - spinBox = new QSpinBox(m_shaderParamsDialog); - spinBox->setRange(param->minimum, param->maximum); - spinBox->setSingleStep(param->step); - spinBox->setValue(param->current); - spinBox->setProperty("slider", QVariant::fromValue(slider)); - slider->setProperty("spinBox", QVariant::fromValue(spinBox)); + QDoubleSpinBox *doubleSpinBox = NULL; + QSpinBox *spinBox = NULL; + QHBoxLayout *box = new QHBoxLayout(); + QSlider *slider = new QSlider(Qt::Horizontal, m_shaderParamsDialog); + double value = lerp(param->minimum, param->maximum, 0, 100, param->current); + double intpart = 0; + bool stepIsFractional = modf(param->step, &intpart); - connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSpinBoxValueChanged(int))); + slider->setRange(0, 100); + slider->setSingleStep(1); + slider->setValue(value); + slider->setProperty("param", QVariant::fromValue(param)); - box->addWidget(spinBox); + connect(slider, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSliderValueChanged(int))); + + box->addWidget(slider); + + if (stepIsFractional) + { + doubleSpinBox = new QDoubleSpinBox(m_shaderParamsDialog); + doubleSpinBox->setRange(param->minimum, param->maximum); + doubleSpinBox->setSingleStep(param->step); + doubleSpinBox->setValue(param->current); + doubleSpinBox->setProperty("slider", QVariant::fromValue(slider)); + slider->setProperty("doubleSpinBox", QVariant::fromValue(doubleSpinBox)); + + connect(doubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onShaderParamDoubleSpinBoxValueChanged(double))); + + box->addWidget(doubleSpinBox); + } + else + { + spinBox = new QSpinBox(m_shaderParamsDialog); + spinBox->setRange(param->minimum, param->maximum); + spinBox->setSingleStep(param->step); + spinBox->setValue(param->current); + spinBox->setProperty("slider", QVariant::fromValue(slider)); + slider->setProperty("spinBox", QVariant::fromValue(spinBox)); + + connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSpinBoxValueChanged(int))); + + box->addWidget(spinBox); + } + + form->addRow(desc, box); } - - form->addRow(desc, box); } + + m_shaderParamsDialog->layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); } m_shaderParamsDialog->resize(720, 480); @@ -2456,6 +2509,17 @@ void MainWindow::onGotStatusMessage(QString msg, unsigned priority, unsigned dur } } +void MainWindow::deferReloadShaderParams() +{ + emit gotReloadShaderParams(); +} + +void MainWindow::onGotReloadShaderParams() +{ + if (m_shaderParamsDialog && m_shaderParamsDialog->isVisible()) + onShaderParamsClicked(); +} + void MainWindow::deferReloadPlaylists() { emit gotReloadPlaylists(); diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index 7fcace03e0..4e679cfeae 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -623,11 +623,23 @@ static void ui_companion_qt_toggle(void *data, bool force) static void ui_companion_qt_event_command(void *data, enum event_command cmd) { ui_companion_qt_t *handle = (ui_companion_qt_t*)data; - - (void)cmd; + ui_window_qt_t *win_handle = (ui_window_qt_t*)handle->window; if (!handle) return; + + switch (cmd) + { + case CMD_EVENT_SHADERS_APPLY_CHANGES: + /* PRESET_LOADED already fires in more situations than APPLY_CHANGES, use that for reloading the params window */ + break; + case CMD_EVENT_SHADER_PRESET_LOADED: + RARCH_LOG("[Qt]: Reloading shader parameters.\n"); + win_handle->qtWindow->deferReloadShaderParams(); + break; + default: + break; + } } static void ui_companion_qt_notify_list_pushed(void *data, file_list_t *list, diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 50943d2a6c..98519dcdf8 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -250,6 +250,18 @@ private: QSpinBox *m_allPlaylistsGridMaxCountSpinBox; }; +class ShaderParamsDialog : public QDialog +{ + Q_OBJECT +public: + ShaderParamsDialog(QWidget *parent = 0); + ~ShaderParamsDialog(); +signals: + void closed(); +protected: + void closeEvent(QCloseEvent *event); +}; + class CoreInfoLabel : public QLabel { Q_OBJECT @@ -365,6 +377,7 @@ signals: void gotLogMessage(const QString &msg); void gotStatusMessage(QString msg, unsigned priority, unsigned duration, bool flush); void gotReloadPlaylists(); + void gotReloadShaderParams(); void showErrorMessageDeferred(QString msg); void extractArchiveDeferred(QString path); @@ -393,6 +406,7 @@ public slots: void reloadPlaylists(); void deferReloadPlaylists(); void onGotReloadPlaylists(); + void onGotReloadShaderParams(); void showWelcomeScreen(); void onIconViewClicked(); void onListViewClicked(); @@ -403,6 +417,7 @@ public slots: void showDocs(); void updateRetroArchNightly(); void onUpdateRetroArchFinished(bool success); + void deferReloadShaderParams(); private slots: void onLoadCoreClicked(const QStringList &extensionFilters = QStringList()); @@ -520,7 +535,7 @@ private: int m_allPlaylistsGridMaxCount; PlaylistEntryDialog *m_playlistEntryDialog; QElapsedTimer m_statusMessageElapsedTimer; - QDialog *m_shaderParamsDialog; + QPointer m_shaderParamsDialog; QNetworkAccessManager *m_networkManager; QProgressDialog *m_updateProgressDialog; QFile m_updateFile; diff --git a/ui/ui_companion_driver.c b/ui/ui_companion_driver.c index 0133e1a56a..a866b6749b 100644 --- a/ui/ui_companion_driver.c +++ b/ui/ui_companion_driver.c @@ -103,6 +103,10 @@ void ui_companion_event_command(enum event_command action) if (ui && ui->event_command) ui->event_command(ui_companion_data, action); +#ifdef HAVE_QT + if (ui_companion_qt.toggle && qt_is_inited) + ui_companion_qt.event_command(ui_companion_qt_data, action); +#endif } void ui_companion_driver_deinit(void) From bf9a8ac4a08b0afcee75b344fc2a1914712ca5b7 Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Tue, 14 Aug 2018 23:12:47 -0500 Subject: [PATCH 015/182] discord: general discord-rpc improvements Now, if the content was loaded from a playlist, the content name will be the playlist entry's title instead of the filename of the content. Also, `state` was modified to show the display name of the core, not the library name. The difference is that the display name shows the platform as well, not just the core name (i.e. "NEC - PC Engine SuperGrafx (Beetle SGX)" instead of "Mednafen SuperGrafx"). --- command.c | 6 +++--- discord/discord.c | 24 +++++++++++++++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/command.c b/command.c index 18ca322b53..1b412a6087 100644 --- a/command.c +++ b/command.c @@ -1336,8 +1336,8 @@ static void command_event_restore_default_shader_preset(void) static void command_event_restore_remaps(void) { - if (rarch_ctl(RARCH_CTL_IS_REMAPS_CORE_ACTIVE, NULL) || - rarch_ctl(RARCH_CTL_IS_REMAPS_CONTENT_DIR_ACTIVE, NULL) || + if (rarch_ctl(RARCH_CTL_IS_REMAPS_CORE_ACTIVE, NULL) || + rarch_ctl(RARCH_CTL_IS_REMAPS_CONTENT_DIR_ACTIVE, NULL) || rarch_ctl(RARCH_CTL_IS_REMAPS_GAME_ACTIVE, NULL)) input_remapping_set_defaults(true); } @@ -2254,7 +2254,7 @@ TODO: Add a setting for these tweaks */ break; case CMD_EVENT_CORE_INFO_DEINIT: core_info_deinit_list(); - core_info_free_current_core(); + //core_info_free_current_core(); break; case CMD_EVENT_CORE_INFO_INIT: { diff --git a/discord/discord.c b/discord/discord.c index 9b7aa2d3bc..d56dcdf6d4 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -21,6 +21,7 @@ #include "../core.h" #include "../core_info.h" #include "../paths.h" +#include "../playlist.h" #include "../msg_hash.h" @@ -80,7 +81,7 @@ void discord_update(enum discord_presence presence) return; if ( - (discord_status != DISCORD_PRESENCE_MENU) && + (discord_status != DISCORD_PRESENCE_MENU) && (discord_status == presence)) return; @@ -104,16 +105,29 @@ void discord_update(enum discord_presence presence) const char *system_name = string_replace_substring( string_to_lower(core_info->core_name), " ", "_"); + char *label = NULL; + playlist_t *current_playlist = playlist_get_cached(); + + if (current_playlist) + { + playlist_get_index_by_path( + current_playlist, path_get(RARCH_PATH_CONTENT), NULL, &label, NULL, NULL, NULL, NULL); + } + + if (!label) + { + label = (char *)path_basename(path_get(RARCH_PATH_BASENAME)); + } + start_time = time(0); - discord_presence.state = system ? system->info.library_name : "---"; - discord_presence.details = path_basename(path_get(RARCH_PATH_BASENAME)); + discord_presence.state = core_info->display_name; + discord_presence.details = label; #if 1 RARCH_LOG("[Discord] system name: %s\n", system_name); + RARCH_LOG("[Discord] current content: %s\n", label); #endif discord_presence.largeImageKey = system_name; - discord_presence.smallImageKey = "base"; - discord_presence.instance = 0; discord_presence.startTimestamp = start_time; From 010412c895c73c42002bb337ad02c5407977001f Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Tue, 14 Aug 2018 23:26:48 -0500 Subject: [PATCH 016/182] discord: simplified some lines --- discord/discord.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/discord/discord.c b/discord/discord.c index d56dcdf6d4..387a5b6cbb 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -109,15 +109,11 @@ void discord_update(enum discord_presence presence) playlist_t *current_playlist = playlist_get_cached(); if (current_playlist) - { playlist_get_index_by_path( current_playlist, path_get(RARCH_PATH_CONTENT), NULL, &label, NULL, NULL, NULL, NULL); - } if (!label) - { label = (char *)path_basename(path_get(RARCH_PATH_BASENAME)); - } start_time = time(0); discord_presence.state = core_info->display_name; From 2d7cb40537711a6298e151b2b5e14dda6b70ef54 Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Tue, 14 Aug 2018 23:40:51 -0500 Subject: [PATCH 017/182] discord: moved core_info changes to separate PR --- command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command.c b/command.c index 1b412a6087..3ae810b915 100644 --- a/command.c +++ b/command.c @@ -2254,7 +2254,7 @@ TODO: Add a setting for these tweaks */ break; case CMD_EVENT_CORE_INFO_DEINIT: core_info_deinit_list(); - //core_info_free_current_core(); + core_info_free_current_core(); break; case CMD_EVENT_CORE_INFO_INIT: { From f53349e3dd0dfcea9a4778e53e09f15b1046df9e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 15 Aug 2018 10:46:01 +0200 Subject: [PATCH 018/182] Move MSVC 2017 files to android/phoenix --- .../msvc-2017-android.NativeActivity.vcxproj | 6 +- ...017-android.NativeActivity.vcxproj.filters | 0 .../msvc-2017-android.Packaging.androidproj | 11 +- .../phoenix}/msvc-2017-android.sln | 4 +- .../AndroidManifest.xml | 43 --- .../msvc-2017-android.Packaging/build.xml | 90 ----- .../res/drawable-hdpi/ic_launcher.png | Bin 1329 -> 0 bytes .../res/drawable-ldpi/ic_launcher.png | Bin 690 -> 0 bytes .../res/drawable-mdpi/ic_launcher.png | Bin 853 -> 0 bytes .../res/drawable-xhdpi/banner.png | Bin 4423 -> 0 bytes .../res/drawable-xhdpi/ic_launcher.png | Bin 1678 -> 0 bytes .../res/drawable-xhdpi/ouya_icon.png | Bin 19152 -> 0 bytes .../res/drawable-xxhdpi/ic_launcher.png | Bin 2524 -> 0 bytes .../res/drawable-xxxhdpi/ic_launcher.png | Bin 3412 -> 0 bytes .../res/drawable/banner.png | Bin 4423 -> 0 bytes .../browser/mainmenu/MainMenuActivity.java | 200 ----------- .../browser/preferences/util/ConfigFile.java | 281 ---------------- .../preferences/util/UserPreferences.java | 300 ----------------- .../retroactivity/RetroActivityCamera.java | 225 ------------- .../retroactivity/RetroActivityCommon.java | 141 -------- .../retroactivity/RetroActivityFuture.java | 87 ----- .../retroactivity/RetroActivityIntent.java | 105 ------ .../retroactivity/RetroActivityLocation.java | 316 ------------------ .../retroactivity/RetroActivityPast.java | 7 - 24 files changed, 6 insertions(+), 1810 deletions(-) rename pkg/{msvc/msvc-2017-android/msvc-2017-android.NativeActivity => android/phoenix}/msvc-2017-android.NativeActivity.vcxproj (98%) rename pkg/{msvc/msvc-2017-android/msvc-2017-android.NativeActivity => android/phoenix}/msvc-2017-android.NativeActivity.vcxproj.filters (100%) rename pkg/{msvc/msvc-2017-android/msvc-2017-android.Packaging => android/phoenix}/msvc-2017-android.Packaging.androidproj (90%) rename pkg/{msvc/msvc-2017-android => android/phoenix}/msvc-2017-android.sln (92%) delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/AndroidManifest.xml delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/build.xml delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-hdpi/ic_launcher.png delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-ldpi/ic_launcher.png delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-mdpi/ic_launcher.png delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-xhdpi/banner.png delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-xhdpi/ic_launcher.png delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-xhdpi/ouya_icon.png delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-xxhdpi/ic_launcher.png delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-xxxhdpi/ic_launcher.png delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable/banner.png delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/mainmenu/MainMenuActivity.java delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/preferences/util/ConfigFile.java delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/preferences/util/UserPreferences.java delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java delete mode 100644 pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityPast.java diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.NativeActivity/msvc-2017-android.NativeActivity.vcxproj b/pkg/android/phoenix/msvc-2017-android.NativeActivity.vcxproj similarity index 98% rename from pkg/msvc/msvc-2017-android/msvc-2017-android.NativeActivity/msvc-2017-android.NativeActivity.vcxproj rename to pkg/android/phoenix/msvc-2017-android.NativeActivity.vcxproj index b491d44aaf..cb5cb62c20 100644 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.NativeActivity/msvc-2017-android.NativeActivity.vcxproj +++ b/pkg/android/phoenix/msvc-2017-android.NativeActivity.vcxproj @@ -35,7 +35,7 @@ - + CompileAsC CompileAsC CompileAsC @@ -45,7 +45,7 @@ CompileAsC CompileAsC - + c++11 c++11 c++11 @@ -55,7 +55,7 @@ c++11 c++11 - + c++11 c++11 c++11 diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.NativeActivity/msvc-2017-android.NativeActivity.vcxproj.filters b/pkg/android/phoenix/msvc-2017-android.NativeActivity.vcxproj.filters similarity index 100% rename from pkg/msvc/msvc-2017-android/msvc-2017-android.NativeActivity/msvc-2017-android.NativeActivity.vcxproj.filters rename to pkg/android/phoenix/msvc-2017-android.NativeActivity.vcxproj.filters diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/msvc-2017-android.Packaging.androidproj b/pkg/android/phoenix/msvc-2017-android.Packaging.androidproj similarity index 90% rename from pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/msvc-2017-android.Packaging.androidproj rename to pkg/android/phoenix/msvc-2017-android.Packaging.androidproj index 8c8883cb06..175d7df105 100644 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/msvc-2017-android.Packaging.androidproj +++ b/pkg/android/phoenix/msvc-2017-android.Packaging.androidproj @@ -44,42 +44,34 @@ true Application - android-23 false Application - android-23 true Application - android-23 false Application - android-23 true Application - android-23 false Application - android-23 true Application - android-23 false Application - android-23 @@ -129,10 +121,9 @@ - - + {e27d73ec-6148-4817-b75c-adaa0c563939} diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.sln b/pkg/android/phoenix/msvc-2017-android.sln similarity index 92% rename from pkg/msvc/msvc-2017-android/msvc-2017-android.sln rename to pkg/android/phoenix/msvc-2017-android.sln index 3b63d42249..45919ce71c 100644 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.sln +++ b/pkg/android/phoenix/msvc-2017-android.sln @@ -5,9 +5,9 @@ VisualStudioVersion = 15.0.26228.9 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "msvc-2017-android", "msvc-2017-android", "{82FC602D-4083-4ED5-858B-A066A4280E4C}" EndProject -Project("{39E2626F-3545-4960-A6E8-258AD8476CE5}") = "msvc-2017-android.Packaging", "msvc-2017-android.Packaging\msvc-2017-android.Packaging.androidproj", "{94B52983-76DE-4545-A708-433C377727C7}" +Project("{39E2626F-3545-4960-A6E8-258AD8476CE5}") = "msvc-2017-android.Packaging", "msvc-2017-android.Packaging.androidproj", "{94B52983-76DE-4545-A708-433C377727C7}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc-2017-android.NativeActivity", "msvc-2017-android.NativeActivity\msvc-2017-android.NativeActivity.vcxproj", "{E27D73EC-6148-4817-B75C-ADAA0C563939}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc-2017-android.NativeActivity", "msvc-2017-android.NativeActivity.vcxproj", "{E27D73EC-6148-4817-B75C-ADAA0C563939}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/AndroidManifest.xml b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/AndroidManifest.xml deleted file mode 100644 index 703a158568..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/AndroidManifest.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/build.xml b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/build.xml deleted file mode 100644 index 4dd78480d3..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/build.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-hdpi/ic_launcher.png b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index d33d1953f9b1d04db50391c6bac98141921050f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1329 zcmV-118o96bJC*&m?vdG;s?A1&Va=AVSc+q`1m}h5(UaFI@x+=ww0YDhORV$Qlx$h!nI1 zT9}?|dFo>B6@kut0lt7<;J(1=AYS(JLo!M8ODYfWpG1+oKizvs37`PVDyyur$|`G< zYs=2Iot-rg9|s@TqiP!fb`?c=C(H7WilTgwW%=VeM^TgycHRNNu06)sID7Sa{ZCa@ zaT8Oo*Z%>4y*Nl)0I*9beV_Lr(hjBcy*-m6Ew^m|*e8Vil=lEK0QwmKo=f4F^8%xSWLM?LdYcV0i+#5$OHfmA;L1_K+pe2K+j>(tV09s0l*7F z$mhHVkO9zV0C-UXl|Us>2~+|VFeOk4v;jcPW)siP&z;2GPZIkmB#^4AXcz|a8jVJg z-#?j5ocHUxjwdH4n+4QtHqo-ISV*JM2pMCDh-g_BHX042l%g!ln*+p=_&^a6d%fO+ z@9A_p&U+YR*lxFxQtITfNQDAYRTX=^o&&@f!;6cHP&kN){eIttlLS&KK&ELTV+);%Qm4~#ow#Y5czJp0OVsN3``GPvT@eS5xR@bcq`SL2=XG7zoxa795(hF( z({<7!5FrG|(jr;q1U%XeIEP)tfsO!2f;yLj?#8a(Se@hHV>_1^EOQ0|% z_Myaq#QqbuEX%^{>uXmuO^duAP1AhwHt8_s?L&zHdDrqfm)M6A0}}hsx|i685(Db> zdVx)uC(iOqs|>>kY}P!f0I8~ql+wV4O9;W?aG1A?Q{w&5LrD~96_WS;uI1{RaI0J zr4TrU1xgcXV}Q~?ii-1CpiG_@OA09tjt%r{9H3nQIFuymyR?ClK#Gea%Q8xm)P=)&2&6ui(FDRzm}A!{SNcF96`{N~Q8cwOakXTCM(( zW+X|{DwWDjlt_}K#mM#X@$vUZM@N!9#>h`S^JR7b0IvYx4FG%t0B-@{+cnQydn|A4 zu^m8+=jH+Ie_jB9X8`ch-q~vaI9l_(w#V|)9$Tz`UJ#LX0bm~%)9|Ui({;{Mdo26# n$p7x(wFTwBzm!#0S?ScjE;XFU#%3qB00000NkvXXu0mjfLn3pG diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-ldpi/ic_launcher.png b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-ldpi/ic_launcher.png deleted file mode 100644 index 555fbd7685f26473a95b1f3899ec7b6ee3fa6c5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 690 zcmV;j0!{siP)#TP3DO(qjWgm$~VaGuZSi=d%Uh)^g*CX=yD9u9{| zrBcM>@gsJiUfHhltSacClPPRs;BIaCdA3VesPpe%~@? zB9Q>N{nx<=plQ};rN`qDzuzyj*-Xac@k*Y{<&sDwBGc(qMx)U>yIV9hIdD&{kjv#F z7!0zF-L-540)eF!RRujX&YBU>1RemCN~NufF|Y^h0MCIju)Fq&yzSw3y8*7Aszn^f zl9?_=uh(1fDwWDI%KJ@Q%DH1b3LF0Q!C-)hkV>U&`KNBE>xfZ&o~F}j)$iTb#gs}V zfX65Cb-Ue&2tJ<=<36>Km|cK;KL1_U^?l&cDPp`X7K>kMwc0mh{dk?bu>%JV9Q?2N Y4fe3ozoLd_yZ`_I07*qoM6N<$g2W^{m;e9( diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-mdpi/ic_launcher.png b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index a338dfb2f9e9657505c316aeb70254359fbe6d09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 853 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 DnS>gY diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-xhdpi/ic_launcher.png b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index 7eb088dc92430c280f73fefbc27acb048035b0e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1678 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 GV*d?_DN<+v diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable/banner.png b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/res/drawable/banner.png deleted file mode 100644 index bcf43ef5aae716ad41a273bad6688c3a3e4fe558..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4423 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 DnS>gY diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/mainmenu/MainMenuActivity.java b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/mainmenu/MainMenuActivity.java deleted file mode 100644 index 88d25d6ee8..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/mainmenu/MainMenuActivity.java +++ /dev/null @@ -1,200 +0,0 @@ -package com.retroarch.browser.mainmenu; - -import com.retroarch.browser.preferences.util.UserPreferences; -import com.retroarch.browser.retroactivity.RetroActivityFuture; -import com.retroarch.browser.retroactivity.RetroActivityPast; - -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.media.AudioManager; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.preference.PreferenceActivity; -import android.preference.PreferenceManager; -import android.provider.Settings; - -import java.util.List; -import java.util.ArrayList; -import android.content.pm.PackageManager; -import android.Manifest; -import android.content.DialogInterface; -import android.app.AlertDialog; -import android.util.Log; - -/** - * {@link PreferenceActivity} subclass that provides all of the - * functionality of the main menu screen. - */ -public final class MainMenuActivity extends PreferenceActivity -{ - final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124; - boolean checkPermissions = false; - - public void showMessageOKCancel(String message, DialogInterface.OnClickListener onClickListener) - { - new AlertDialog.Builder(this).setMessage(message) - .setPositiveButton("OK", onClickListener).setCancelable(false) - .setNegativeButton("Cancel", null).create().show(); - } - - private boolean addPermission(List permissionsList, String permission) - { - if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) - { - permissionsList.add(permission); - - // Check for Rationale Option - if (!shouldShowRequestPermissionRationale(permission)) - return false; - } - - return true; - } - - public void checkRuntimePermissions() - { - if (android.os.Build.VERSION.SDK_INT >= 23) - { - // Android 6.0+ needs runtime permission checks - List permissionsNeeded = new ArrayList(); - final List permissionsList = new ArrayList(); - - if (!addPermission(permissionsList, Manifest.permission.READ_EXTERNAL_STORAGE)) - permissionsNeeded.add("Read External Storage"); - if (!addPermission(permissionsList, Manifest.permission.WRITE_EXTERNAL_STORAGE)) - permissionsNeeded.add("Write External Storage"); - - if (permissionsList.size() > 0) - { - checkPermissions = true; - - if (permissionsNeeded.size() > 0) - { - // Need Rationale - Log.i("MainMenuActivity", "Need to request external storage permissions."); - - String message = "You need to grant access to " + permissionsNeeded.get(0); - - for (int i = 1; i < permissionsNeeded.size(); i++) - message = message + ", " + permissionsNeeded.get(i); - - showMessageOKCancel(message, - new DialogInterface.OnClickListener() - { - @Override - public void onClick(DialogInterface dialog, int which) - { - if (which == AlertDialog.BUTTON_POSITIVE) - { - requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), - REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS); - - Log.i("MainMenuActivity", "User accepted request for external storage permissions."); - } - } - }); - } - else - { - requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), - REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS); - - Log.i("MainMenuActivity", "Requested external storage permissions."); - } - } - } - - if (!checkPermissions) - { - finalStartup(); - } - } - - public void finalStartup() - { - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - Intent retro; - - if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) - { - retro = new Intent(this, RetroActivityFuture.class); - } - else - { - retro = new Intent(this, RetroActivityPast.class); - } - - retro.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - - startRetroActivity( - retro, - null, - prefs.getString("libretro_path", getApplicationInfo().dataDir + "/cores/"), - UserPreferences.getDefaultConfigPath(this), - Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD), - getApplicationInfo().dataDir, - getApplicationInfo().sourceDir); - startActivity(retro); - finish(); - } - - @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) - { - switch (requestCode) - { - case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: - for (int i = 0; i < permissions.length; i++) - { - if(grantResults[i] == PackageManager.PERMISSION_GRANTED) - { - Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was granted."); - } - else - { - Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was not granted."); - } - } - - break; - default: - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - break; - } - - finalStartup(); - } - - public static void startRetroActivity(Intent retro, String contentPath, String corePath, - String configFilePath, String imePath, String dataDirPath, String dataSourcePath) - { - if (contentPath != null) { - retro.putExtra("ROM", contentPath); - } - retro.putExtra("LIBRETRO", corePath); - retro.putExtra("CONFIGFILE", configFilePath); - retro.putExtra("IME", imePath); - retro.putExtra("DATADIR", dataDirPath); - retro.putExtra("APK", dataSourcePath); - retro.putExtra("SDCARD", Environment.getExternalStorageDirectory().getAbsolutePath()); - retro.putExtra("DOWNLOADS", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()); - retro.putExtra("SCREENSHOTS", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()); - String external = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/com.retroarch/files"; - retro.putExtra("EXTERNAL", external); - } - - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - // Bind audio stream to hardware controls. - setVolumeControlStream(AudioManager.STREAM_MUSIC); - - UserPreferences.updateConfigFile(this); - - checkRuntimePermissions(); - } -} diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/preferences/util/ConfigFile.java b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/preferences/util/ConfigFile.java deleted file mode 100644 index eccaf730cb..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/preferences/util/ConfigFile.java +++ /dev/null @@ -1,281 +0,0 @@ -package com.retroarch.browser.preferences.util; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.Map; - -import android.util.Log; - -/** - * Represents a configuration file that works off of a key-value pair - * in the form [key name] = "[value]". - */ -public final class ConfigFile -{ - // Map containing all of the key-value pairs. - private final HashMap map = new HashMap(); - - /** - * Constructor - */ - public ConfigFile() - { - } - - /** - * Constructor - * - * @param filePath The path to the configuration file to open. - */ - public ConfigFile(String filePath) - { - if (filePath == null) - throw new IllegalArgumentException("filePath cannot be null."); - - try - { - open(filePath); - } - catch (IOException ioe) - { - Log.e("ConfigFile", "Stream reading the configuration file was suddenly closed for an unknown reason."); - } - } - - /** - * Parses a configuration file from the given stream - * and appends the parsed values to the key-value map. - * - * @param stream The {@link InputStream} containing the configuration file to parse. - */ - public void append(InputStream stream) throws IOException - { - BufferedReader br = new BufferedReader(new InputStreamReader(stream)); - - String line; - while ((line = br.readLine()) != null) - parseLine(line); - - br.close(); - } - - /** - * Opens a configuration file given by configPath - * and parses all of its key-value pairs, adding - * them to the key-value map. - * - * @param configPath Path to the configuration file to parse. - */ - public void open(String configPath) throws IOException - { - clear(); - append(new FileInputStream(configPath)); - } - - private void parseLine(String line) - { - String[] tokens = line.split("=", 2); - if (tokens.length < 2) - return; - - for (int i = 0; i < tokens.length; i++) - tokens[i] = tokens[i].trim(); - - String key = tokens[0]; - String value = tokens[1]; - - if (value.startsWith("\"")) - value = value.substring(1, value.lastIndexOf('\"')); - else - value = value.split(" ")[0]; - - if (value.length() > 0) - map.put(key, value); - } - - /** - * Clears the key-value map of all currently set keys and values. - */ - public void clear() - { - map.clear(); - } - - /** - * Writes the currently set key-value pairs to - * - * @param path The path to save the - * - * @throws IOException - */ - public void write(String path) throws IOException - { - PrintWriter writer = new PrintWriter(path); - - for (Map.Entry entry : map.entrySet()) - { - writer.println(entry.getKey() + " = \"" + entry.getValue() + "\""); - } - - writer.close(); - } - - /** - * Checks if a key exists in the {@link HashMap} - * backing this ConfigFile instance. - * - * @param key The key to check for. - * - * @return true if the key exists in the HashMap backing - * this ConfigFile; false if it doesn't. - */ - public boolean keyExists(String key) - { - return map.containsKey(key); - } - - /** - * Sets a key to the given String value. - * - * @param key The key to set the String value to. - * @param value The String value to set to the key. - */ - public void setString(String key, String value) - { - map.put(key, value); - } - - /** - * Sets a key to the given boolean value. - * - * @param key The key to set the boolean value to. - * @param value The boolean value to set to the key. - */ - public void setBoolean(String key, boolean value) - { - map.put(key, Boolean.toString(value)); - } - - /** - * Sets a key to the given Integer value. - * - * @param key The key to set the Integer value to. - * @param value The Integer value to set to the key. - */ - public void setInt(String key, int value) - { - map.put(key, Integer.toString(value)); - } - - /** - * Sets a key to the given double value. - * - * @param key The key to set the double value to. - * @param value The double value to set to the key. - */ - public void setDouble(String key, double value) - { - map.put(key, Double.toString(value)); - } - - /** - * Sets a key to the given float value. - * - * @param key The key to set the float value to. - * @param value The float value to set to the key. - */ - public void setFloat(String key, float value) - { - map.put(key, Float.toString(value)); - } - - /** - * Gets the String value associated with the given key. - * - * @param key The key to get the String value from. - * - * @return the String object associated with the given key. - */ - public String getString(String key) - { - String ret = map.get(key); - - if (ret != null) - return ret; - else - return null; - } - - /** - * Gets the Integer value associated with the given key. - * - * @param key The key to get the Integer value from. - * - * @return the Integer value associated with the given key. - */ - public int getInt(String key) - { - String str = getString(key); - - if (str != null) - return Integer.parseInt(str); - else - throw new IllegalArgumentException("Config key '" + key + "' is invalid."); - } - - /** - * Gets the double value associated with the given key. - * - * @param key The key to get the double value from. - * - * @return the double value associated with the given key. - */ - public double getDouble(String key) - { - String str = getString(key); - - if (str != null) - return Double.parseDouble(str); - else - throw new IllegalArgumentException("Config key '" + key + "' is invalid."); - } - - /** - * Gets the float value associated with the given key. - * - * @param key The key to get the float value from. - * - * @return the float value associated with the given key. - */ - public float getFloat(String key) - { - String str = getString(key); - - if (str != null) - return Float.parseFloat(str); - else - throw new IllegalArgumentException("Config key '" + key + "' is invalid."); - } - - /** - * Gets the boolean value associated with the given key. - * - * @param key The key to get the boolean value from. - * - * @return the boolean value associated with the given key. - */ - public boolean getBoolean(String key) - { - String str = getString(key); - - if (str != null) - return Boolean.parseBoolean(str); - else - throw new IllegalArgumentException("Config key '" + key + "' is invalid."); - } -} diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/preferences/util/UserPreferences.java b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/preferences/util/UserPreferences.java deleted file mode 100644 index 2e1ec9ed61..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/preferences/util/UserPreferences.java +++ /dev/null @@ -1,300 +0,0 @@ -package com.retroarch.browser.preferences.util; - -import java.io.File; -import java.io.IOException; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.SharedPreferences; -import android.media.AudioManager; -import android.media.AudioTrack; -import android.os.Build; -import android.preference.PreferenceManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.util.Log; - -/** - * Utility class for retrieving, saving, or loading preferences. - */ -public final class UserPreferences -{ - // Logging tag. - private static final String TAG = "UserPreferences"; - - // Disallow explicit instantiation. - private UserPreferences() - { - } - - /** - * Retrieves the path to the default location of the libretro config. - * - * @param ctx the current {@link Context} - * - * @return the path to the default location of the libretro config. - */ - public static String getDefaultConfigPath(Context ctx) - { - // Internal/External storage dirs. - final String internal = ctx.getFilesDir().getAbsolutePath(); - String external = null; - - // Get the App's external storage folder - final String state = android.os.Environment.getExternalStorageState(); - if (android.os.Environment.MEDIA_MOUNTED.equals(state)) { - File extsd = ctx.getExternalFilesDir(null); - external = extsd.getAbsolutePath(); - } - - // Native library directory and data directory for this front-end. - final String dataDir = ctx.getApplicationInfo().dataDir; - final String coreDir = dataDir + "/cores/"; - - // Get libretro name and path - final SharedPreferences prefs = getPreferences(ctx); - final String libretro_path = prefs.getString("libretro_path", coreDir); - - // Check if global config is being used. Return true upon failure. - final boolean globalConfigEnabled = prefs.getBoolean("global_config_enable", true); - - String append_path; - // If we aren't using the global config. - if (!globalConfigEnabled && !libretro_path.equals(coreDir)) - { - String sanitized_name = sanitizeLibretroPath(libretro_path); - append_path = File.separator + sanitized_name + ".cfg"; - } - else // Using global config. - { - append_path = File.separator + "retroarch.cfg"; - } - - if (external != null) - { - String confPath = external + append_path; - if (new File(confPath).exists()) - return confPath; - } - else if (internal != null) - { - String confPath = internal + append_path; - if (new File(confPath).exists()) - return confPath; - } - else - { - String confPath = "/mnt/extsd" + append_path; - if (new File(confPath).exists()) - return confPath; - } - - // Config file does not exist. Create empty one. - - // emergency fallback - String new_path = "/mnt/sd" + append_path; - - if (external != null) - new_path = external + append_path; - else if (internal != null) - new_path = internal + append_path; - else if (dataDir != null) - new_path = dataDir + append_path; - - try { - new File(new_path).createNewFile(); - } - catch (IOException e) - { - Log.e(TAG, "Failed to create config file to: " + new_path); - } - return new_path; - } - - /** - * Updates the libretro configuration file - * with new values if settings have changed. - * - * @param ctx the current {@link Context}. - */ - public static void updateConfigFile(Context ctx) - { - String path = getDefaultConfigPath(ctx); - ConfigFile config = new ConfigFile(path); - - Log.i(TAG, "Writing config to: " + path); - - final String dataDir = ctx.getApplicationInfo().dataDir; - final String coreDir = dataDir + "/cores/"; - - final SharedPreferences prefs = getPreferences(ctx); - - config.setString("libretro_directory", coreDir); - config.setInt("audio_out_rate", getOptimalSamplingRate(ctx)); - - try - { - int version = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0).versionCode; - final String dst_path = dataDir; - final String dst_path_subdir = "assets"; - - Log.i(TAG, "dst dir is: " + dst_path); - Log.i(TAG, "dst subdir is: " + dst_path_subdir); - - config.setBoolean("log_verbosity", true); - config.setString("bundle_assets_src_path", ctx.getApplicationInfo().sourceDir); - config.setString("bundle_assets_dst_path", dst_path); - config.setString("bundle_assets_dst_path_subdir", dst_path_subdir); - config.setInt("bundle_assets_extract_version_current", version); - } - catch (NameNotFoundException ignored) - { - } - - // Refactor this entire mess and make this usable for per-core config - if (Build.VERSION.SDK_INT >= 17 && prefs.getBoolean("audio_latency_auto", true)) - { - config.setInt("audio_block_frames", getLowLatencyBufferSize(ctx)); - } - - try - { - config.write(path); - } - catch (IOException e) - { - Log.e(TAG, "Failed to save config file to: " + path); - } - } - - private static void readbackString(ConfigFile cfg, SharedPreferences.Editor edit, String key) - { - if (cfg.keyExists(key)) - edit.putString(key, cfg.getString(key)); - else - edit.remove(key); - } - - private static void readbackBool(ConfigFile cfg, SharedPreferences.Editor edit, String key) - { - if (cfg.keyExists(key)) - edit.putBoolean(key, cfg.getBoolean(key)); - else - edit.remove(key); - } - - private static void readbackDouble(ConfigFile cfg, SharedPreferences.Editor edit, String key) - { - if (cfg.keyExists(key)) - edit.putFloat(key, (float)cfg.getDouble(key)); - else - edit.remove(key); - } - - /* - private static void readbackFloat(ConfigFile cfg, SharedPreferences.Editor edit, String key) - { - if (cfg.keyExists(key)) - edit.putFloat(key, cfg.getFloat(key)); - else - edit.remove(key); - } - */ - - /** - private static void readbackInt(ConfigFile cfg, SharedPreferences.Editor edit, String key) - { - if (cfg.keyExists(key)) - edit.putInt(key, cfg.getInt(key)); - else - edit.remove(key); - } - */ - - /** - * Sanitizes a libretro core path. - * - * @param path The path to the libretro core. - * - * @return the sanitized libretro path. - */ - private static String sanitizeLibretroPath(String path) - { - String sanitized_name = path.substring( - path.lastIndexOf('/') + 1, - path.lastIndexOf('.')); - sanitized_name = sanitized_name.replace("neon", ""); - sanitized_name = sanitized_name.replace("libretro_", ""); - - return sanitized_name; - } - - /** - * Gets a {@link SharedPreferences} instance containing current settings. - * - * @param ctx the current {@link Context}. - * - * @return A SharedPreference instance containing current settings. - */ - public static SharedPreferences getPreferences(Context ctx) - { - return PreferenceManager.getDefaultSharedPreferences(ctx); - } - - /** - * Gets the optimal sampling rate for low-latency audio playback. - * - * @param ctx the current {@link Context}. - * - * @return the optimal sampling rate for low-latency audio playback in Hz. - */ - @TargetApi(17) - private static int getLowLatencyOptimalSamplingRate(Context ctx) - { - AudioManager manager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE); - - return Integer.parseInt(manager - .getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)); - } - - /** - * Gets the optimal buffer size for low-latency audio playback. - * - * @param ctx the current {@link Context}. - * - * @return the optimal output buffer size in decimal PCM frames. - */ - @TargetApi(17) - private static int getLowLatencyBufferSize(Context ctx) - { - AudioManager manager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE); - int buffersize = Integer.parseInt(manager - .getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER)); - Log.i(TAG, "Queried ideal buffer size (frames): " + buffersize); - return buffersize; - } - - /** - * Gets the optimal audio sampling rate. - *

- * On Android 4.2+ devices this will retrieve the optimal low-latency sampling rate, - * since Android 4.2 adds support for low latency audio in general. - *

- * On other devices, it simply returns the regular optimal sampling rate - * as returned by the hardware. - * - * @param ctx The current {@link Context}. - * - * @return the optimal audio sampling rate in Hz. - */ - private static int getOptimalSamplingRate(Context ctx) - { - int ret; - if (Build.VERSION.SDK_INT >= 17) - ret = getLowLatencyOptimalSamplingRate(ctx); - else - ret = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC); - - Log.i(TAG, "Using sampling rate: " + ret + " Hz"); - return ret; - } -} diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java deleted file mode 100644 index d51d7f768f..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java +++ /dev/null @@ -1,225 +0,0 @@ -package com.retroarch.browser.retroactivity; - -import java.io.IOException; - -import com.retroarch.browser.preferences.util.UserPreferences; - -import android.annotation.SuppressLint; -import android.content.SharedPreferences; -import android.graphics.SurfaceTexture; -import android.graphics.SurfaceTexture.OnFrameAvailableListener; -import android.hardware.Camera; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; - -//For Android 3.0 and up - -/** - * Class which provides {@link Camera} functionality - * to {@link RetroActivityFuture}. - */ -@SuppressLint("NewApi") -public class RetroActivityCamera extends RetroActivityCommon -{ - private Camera mCamera = null; - private long lastTimestamp = 0; - private SurfaceTexture texture; - private boolean updateSurface = true; - private boolean camera_service_running = false; - - /** - * Executed when the {@link Camera} - * is staring to capture. - */ - public void onCameraStart() - { - if (camera_service_running) - return; - - if (mCamera != null) - mCamera.startPreview(); - camera_service_running = true; - } - - /** - * Executed when the {@link Camera} is done capturing. - *

ZUOE}yVhStFl_*s-S*#r*=GMR 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

usYe*yR%T8rsQ^ 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 z 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

pFlzI&Xn^C>T@!U_sGJjD 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

Q!<`k3mQeAKw1{6#bmhG+!Y?XVEfk03QHy{g( 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Ν6(+q*iB%1m{vIuRbDl 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�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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/proguard.txt b/pkg/android/phoenix64/libs/googleplay/proguard.txt new file mode 100644 index 0000000000..0c9693a2c0 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/proguard.txt @@ -0,0 +1,20 @@ +-keep class * extends java.util.ListResourceBundle { + protected Object[][] getContents(); +} + +# Keep SafeParcelable value, needed for reflection. This is required to support backwards +# compatibility of some classes. +-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable { + public static final *** NULL; +} + +# Keep the names of classes/members we need for client functionality. +-keepnames @com.google.android.gms.common.annotation.KeepName class * +-keepclassmembernames class * { + @com.google.android.gms.common.annotation.KeepName *; +} + +# Needed for Parcelable/SafeParcelable Creators to not get stripped +-keepnames class * implements android.os.Parcelable { + public static final ** CREATOR; +} \ No newline at end of file diff --git a/pkg/android/phoenix64/libs/googleplay/project.properties b/pkg/android/phoenix64/libs/googleplay/project.properties new file mode 100644 index 0000000000..93c8c3c08d --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-21 +android.library=true diff --git a/pkg/android/phoenix64/libs/googleplay/res/color/common_signin_btn_text_dark.xml b/pkg/android/phoenix64/libs/googleplay/res/color/common_signin_btn_text_dark.xml new file mode 100644 index 0000000000..a615ba2747 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/color/common_signin_btn_text_dark.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/res/color/common_signin_btn_text_light.xml b/pkg/android/phoenix64/libs/googleplay/res/color/common_signin_btn_text_light.xml new file mode 100644 index 0000000000..662066899b --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/color/common_signin_btn_text_light.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0f9e7917e057894c3f87938fce528dc778385c9a GIT binary patch literal 1811 zcmV+u2kiKXP)zp|h zwS#$0TA^w}FlXj#0f2U`SD#j>nzTaIq!p?rtxz>-g{n!_TCY)3N-~6yF|z^yF|WQ5 zVoyq$FCnz4ELEtYDEi*}t0|>R0AOl1%au}hg%B$f31CS=rIduV_RW;iYl!%xQtC@0 z8l{vvF~%z?rB}=KiRiu%;t>F_)_RACrmpChN#jDr7`3(beP-?x(RbZ$_n(Nz76aRP zo^KRI@kiT6gb>@tnC+(Ht4pJUIWwcR_P5O32LPXC+3g9D006)kbDxO5Efrx= z6gOgwy2708F4tkU`#%!I3rOP3W3MGW_S(beUC9#;fZ>{~%Irqxpo?(npk4B?6 zLI`gn;xNmyKT9b`O~!Uo8lQTll%rm+_i3Kzn=!^K0HBz;>%D*1dmrFn3tPj%SXLNg zKAUEzq?A-q6vt*xX4a+8*PL@lw;v)FTI<2Wu47Rrs)C4$Znt}zneT)UUWzdq0KgdI zrIgafVLc(lH?usa5JKO3|IV!M2qC;tK1ReJwAO!F)HN(MnL|WYNzzzWV~p2A2oI%{cCs!J6-4x?TsBS(Gyni14iNDuIYq?%MaH^Pp@a~R zLI^LHinO)%gHEUO_sN_{O1Uqk+$xt1hr{<$N*4hDlu~y)oz8Akv95G;!5H%mB2Kyr z#yR&vp6BPrIRIE-mk?NFEDe)%mx7TcynPADvIJ)%&f93`*zCbOQ&(6#v2OP z#=f`&fPjbtBHBa591#OEix}hU%v{deF@*3|p67)z=D$tHIgiGKN-0Te?OQ3OD*%9q zIFM3))#-E|A>va{r=^r0SZlAB(*-!Ngx}U$|8JU$ptb(u(1wvxRvLq6r4gZGjGgg@ zLJt5y2=P^xWnWJ7%MT%<*z5KFVXYm65U#_M@l!hIE>F7!l~PN~-WwUrt+l^C6p4s- zyWMW3NM*7t`%WqKIg}omtm9=h&BBEmui=iSd@1GECq0KT=KBffVdZx4!i5SU9GljK z5T{D~gb?4C4p;6XEL^CGnd{V^HzNAd`^RUE>#Q^}Mjf+mLkO2nbCN>?4*-(ZdgbZC z!i6HDo$_%A;aVN9e3B5t2EdV{@YLFG*(_WrW6Xa5plp>WYwi2q`wMl?F&d42!OZJK zw3B7o-9^WE8k*=)!5H&50Pv;a%sKbra5%i-yz;D_WS+6dhgeZqPUz=dKmz^aA5gLW`1exnI}XX648Ar<+j#(=e+cyGL0{awbr{@ z>s^2Y2O-9&$0-97Q6M5$H)~%d%eI2kDxbqV3++?EHED&aNh?%MTA^xE^;6lFCt%y7 zYSIc-lggjUz6ifiKV;suR`n>}+uO?rgTckchIIZI31h<(%J=(u+I{~dw zHED&aNh?%MkeLBySg$yHR(#fHfvMLub9Q6K{{x7l2QBO9gO>mR002ovPDHLkV1hkw BUr7J} literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..570e4322523687b58c4bbfa70be8353504911ffb GIT binary patch literal 1846 zcmV-62g&$}P)C%R zTmcyyTo{K-pb}FA_zro`H{dhnJr8-$V_peGQcj8h!BHv!6EH@$6$`ODx4xV_>}nY; zyQ7iV*_F-ws4j=Z zFH}oP3`Yy=341(P&w}(*GPf@ zgo=ZRV)q-C>QYrP!=!P-OuRwR`7US(PK zqWAt8B6_H`-e%^J_da&cZF%p1TCdN{Un-^U0gxz)9x(IV_17xtTqtX8nCJPgL}Zhh zzZeV#9}!I#1K$AH$+GN{wf5(jtP;HUTR{-)#BsdSwS8^r)R~J2<#~QXL^c6bX_|gg z6KP7Cre8Ai?OG94RrRX1_S7T{I~6L=^Q$6q4gi>Wr|A_+lH}h2Y^_KaMe%%>_8o`L zg!10Awf5@tLCnLZ`bsIo%y(w)@l;p#9hc68s;cTd0DW*RB1dK^f*`m%QxrMpPQ~lj z<%rstDTh(^q8n<}r0&f=&r40o-y^^FTE%kqlW`qmLmrz4S>ziO&D8jW7|-k+U3 z@8c+nzWG5$H_+LL3WA`R?Wp(uvN2|`sEzktiAVyBM^lm{pEf;1Liel>Dh{!}y^l(}ISV{IkDP;zO!6zbe z%NVoioJ#p?Rg>rfVFm`s;bu)J;Pdiy?#wZ|BIsN{bluGrTHi#k}wSS z0qg_7a5%g?Q^kM3)#+eu8BPEYIlQmvoO{j~b9Y`QlbH=O->a8RLW2+hi0B~^O@mV+ z`gWPNu2m?d)IDqMleMBK&-1su_kWu#XQpVahg$2K^|Ik`_=flX!sPpZ#c{mw*v=1S zt(yyR9N#9Q+1V{F%ks@U&!1k4Q43hvh!PPl%krFa?u>|}A`$}#Cz}hiurcN}5ed^Y zy}c?Mo9JAq$%ewSliX4Oz)t+hJ~J0YWJN?d=bjajdd7jQwJ#P$QN?lGxRhB1oeAZ= z53($K$$P&AfQaZ}5Cs2;we}|`xz9lY4}g!NXzk%a7eXCcMp$dF8e`fX$f&n_2AF0P)_On#=s>6>Nj?Wq zPnGCA&)=-7>P*{vj7FmuMC3^#dXT2+_Ofj}2}_TonAyg0e6uKuH}KtTl@vwsmNDk5 zAPBw)!*Fjl=oAqu%kqLT<~b3$z|42kH2wR$;B*~y5^#oLxKBiXDvIK@TByLzxl7Ku zOJ!MFBFZKXTSO$B#9azNrnUYcNs_hur8=E0VYJq{*82UjEYBNbp7P$G2asZ%@(o1f ziOH|OJrNC=`A!f7J5dxpI4z^7PUnl_D2jHYDB14clYu3uP-7QoQjjVoso|m-uuISG#nB+>b2Vha2CgS zMIS)~;{&#P0OlU-5a8%T@))N+9(Skj(XfFbeF)W#{(syZgI=hX^g^|SLPx# literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..570e4322523687b58c4bbfa70be8353504911ffb GIT binary patch literal 1846 zcmV-62g&$}P)C%R zTmcyyTo{K-pb}FA_zro`H{dhnJr8-$V_peGQcj8h!BHv!6EH@$6$`ODx4xV_>}nY; zyQ7iV*_F-ws4j=Z zFH}oP3`Yy=341(P&w}(*GPf@ zgo=ZRV)q-C>QYrP!=!P-OuRwR`7US(PK zqWAt8B6_H`-e%^J_da&cZF%p1TCdN{Un-^U0gxz)9x(IV_17xtTqtX8nCJPgL}Zhh zzZeV#9}!I#1K$AH$+GN{wf5(jtP;HUTR{-)#BsdSwS8^r)R~J2<#~QXL^c6bX_|gg z6KP7Cre8Ai?OG94RrRX1_S7T{I~6L=^Q$6q4gi>Wr|A_+lH}h2Y^_KaMe%%>_8o`L zg!10Awf5@tLCnLZ`bsIo%y(w)@l;p#9hc68s;cTd0DW*RB1dK^f*`m%QxrMpPQ~lj z<%rstDTh(^q8n<}r0&f=&r40o-y^^FTE%kqlW`qmLmrz4S>ziO&D8jW7|-k+U3 z@8c+nzWG5$H_+LL3WA`R?Wp(uvN2|`sEzktiAVyBM^lm{pEf;1Liel>Dh{!}y^l(}ISV{IkDP;zO!6zbe z%NVoioJ#p?Rg>rfVFm`s;bu)J;Pdiy?#wZ|BIsN{bluGrTHi#k}wSS z0qg_7a5%g?Q^kM3)#+eu8BPEYIlQmvoO{j~b9Y`QlbH=O->a8RLW2+hi0B~^O@mV+ z`gWPNu2m?d)IDqMleMBK&-1su_kWu#XQpVahg$2K^|Ik`_=flX!sPpZ#c{mw*v=1S zt(yyR9N#9Q+1V{F%ks@U&!1k4Q43hvh!PPl%krFa?u>|}A`$}#Cz}hiurcN}5ed^Y zy}c?Mo9JAq$%ewSliX4Oz)t+hJ~J0YWJN?d=bjajdd7jQwJ#P$QN?lGxRhB1oeAZ= z53($K$$P&AfQaZ}5Cs2;we}|`xz9lY4}g!NXzk%a7eXCcMp$dF8e`fX$f&n_2AF0P)_On#=s>6>Nj?Wq zPnGCA&)=-7>P*{vj7FmuMC3^#dXT2+_Ofj}2}_TonAyg0e6uKuH}KtTl@vwsmNDk5 zAPBw)!*Fjl=oAqu%kqLT<~b3$z|42kH2wR$;B*~y5^#oLxKBiXDvIK@TByLzxl7Ku zOJ!MFBFZKXTSO$B#9azNrnUYcNs_hur8=E0VYJq{*82UjEYBNbp7P$G2asZ%@(o1f ziOH|OJrNC=`A!f7J5dxpI4z^7PUnl_D2jHYDB14clYu3uP-7QoQjjVoso|m-uuISG#nB+>b2Vha2CgS zMIS)~;{&#P0OlU-5a8%T@))N+9(Skj(XfFbeF)W#{(syZgI=hX^g^|SLPx# literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0f9e7917e057894c3f87938fce528dc778385c9a GIT binary patch literal 1811 zcmV+u2kiKXP)zp|h zwS#$0TA^w}FlXj#0f2U`SD#j>nzTaIq!p?rtxz>-g{n!_TCY)3N-~6yF|z^yF|WQ5 zVoyq$FCnz4ELEtYDEi*}t0|>R0AOl1%au}hg%B$f31CS=rIduV_RW;iYl!%xQtC@0 z8l{vvF~%z?rB}=KiRiu%;t>F_)_RACrmpChN#jDr7`3(beP-?x(RbZ$_n(Nz76aRP zo^KRI@kiT6gb>@tnC+(Ht4pJUIWwcR_P5O32LPXC+3g9D006)kbDxO5Efrx= z6gOgwy2708F4tkU`#%!I3rOP3W3MGW_S(beUC9#;fZ>{~%Irqxpo?(npk4B?6 zLI`gn;xNmyKT9b`O~!Uo8lQTll%rm+_i3Kzn=!^K0HBz;>%D*1dmrFn3tPj%SXLNg zKAUEzq?A-q6vt*xX4a+8*PL@lw;v)FTI<2Wu47Rrs)C4$Znt}zneT)UUWzdq0KgdI zrIgafVLc(lH?usa5JKO3|IV!M2qC;tK1ReJwAO!F)HN(MnL|WYNzzzWV~p2A2oI%{cCs!J6-4x?TsBS(Gyni14iNDuIYq?%MaH^Pp@a~R zLI^LHinO)%gHEUO_sN_{O1Uqk+$xt1hr{<$N*4hDlu~y)oz8Akv95G;!5H%mB2Kyr z#yR&vp6BPrIRIE-mk?NFEDe)%mx7TcynPADvIJ)%&f93`*zCbOQ&(6#v2OP z#=f`&fPjbtBHBa591#OEix}hU%v{deF@*3|p67)z=D$tHIgiGKN-0Te?OQ3OD*%9q zIFM3))#-E|A>va{r=^r0SZlAB(*-!Ngx}U$|8JU$ptb(u(1wvxRvLq6r4gZGjGgg@ zLJt5y2=P^xWnWJ7%MT%<*z5KFVXYm65U#_M@l!hIE>F7!l~PN~-WwUrt+l^C6p4s- zyWMW3NM*7t`%WqKIg}omtm9=h&BBEmui=iSd@1GECq0KT=KBffVdZx4!i5SU9GljK z5T{D~gb?4C4p;6XEL^CGnd{V^HzNAd`^RUE>#Q^}Mjf+mLkO2nbCN>?4*-(ZdgbZC z!i6HDo$_%A;aVN9e3B5t2EdV{@YLFG*(_WrW6Xa5plp>WYwi2q`wMl?F&d42!OZJK zw3B7o-9^WE8k*=)!5H&50Pv;a%sKbra5%i-yz;D_WS+6dhgeZqPUz=dKmz^aA5gLW`1exnI}XX648Ar<+j#(=e+cyGL0{awbr{@ z>s^2Y2O-9&$0-97Q6M5$H)~%d%eI2kDxbqV3++?EHED&aNh?%MTA^xE^;6lFCt%y7 zYSIc-lggjUz6ifiKV;suR`n>}+uO?rgTckchIIZI31h<(%J=(u+I{~dw zHED&aNh?%MkeLBySg$yHR(#fHfvMLub9Q6K{{x7l2QBO9gO>mR002ovPDHLkV1hkw BUr7J} literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..f507b9f7da2832fbb0aff023afcdaafa63abc36c GIT binary patch literal 2100 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 FV1h=&1F`@B literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_normal_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_normal_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..aea3c0d16856a881fbb167177ad1132f78e6e9dc GIT binary patch literal 2050 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 fE92;1&Ps{4R@i>Sp@00000NkvXXu0mjfWzh9J literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_pressed_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_pressed_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..f4ab2f2a512cbe85edd7bc6cda358de3c11e6d83 GIT binary patch literal 2224 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 BPjdhO literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_disabled_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_disabled_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..bbcde39cf0cdeb33a2d698be676aa1219dddcb9d GIT binary patch literal 1927 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_disabled_focus_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_disabled_focus_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..53957b698fca43ac7baecbd4b13d4b57618154e5 GIT binary patch literal 1957 zcmV;W2U_@vP)KzgA3zu2vlN<09F18xz9h~H|3s-+~<-@ClpDU6aj*xR01YojBG0wVt0<+{pDg; z>(QcJ$@0#QwECW^tX|-FFPItPSmDO&*pvK;&N0BM>p}=2ArzgH5Q@%8 z2u0^4graja>%*&m`1EY7^;Hmsiz<*F3C%-&6;p!VpF`|F;Nt40r1Uj z%)D zWoPXyj=$FW3BxelwAMBsqN1`aFBxNQ?Q`h3231OZH*3eiVDPH<{`BbkK98d4hbJnu z=tOHZVGsnxWQe@?7wfw2O*_VWubDXkhP7alBwx<@4rcB#^QqCRvvF|oWLoVfOp@dl zfaYac7e(>wX)WHOC@x}H6P9rt-<09HlcCiRYOSjzN&bpP5Se*3%d&TiqBy_PZR4B^ z2ZO;&*4keH7$iyZp)qFAX4%Bi(fTFK7&A~x{i!I5E6%w!0EU^)*cKy--V zy0g2%C??P2oHKP@?`mN)^SDO!-k&atVthYIM0FHJ4_o`k#M~_8K1yp{_j71oYNgb@=C)DyOb7r( z^pJ?g9ot0oV@t&rbJl4Hwbu8nwNE!TMR}gT^_xo>o@6U}s z|5qHxQm8(n}{Y`!EsrZZ|8abY$t^h3%9VEkeO9kmS>!ErANo|&67Z^&Bv za#0jj9LF<<@5J%eS_r-OL6&8&c<O|tgL*R zW!aXs_7yz3Uk%E#e0HzPvW%)MhgKRUd7l4jCxAq>+3WRY2Cykj)BhS{K0)IL1b1f2 zh~+f*5Eeyoj+w{ZF2z8!`^HG;;#pB?5rJCj=h_$Z2`i)M+n5yD+V zXV%)wbzL8H@uTK(&jI6^HL@7e5}SJnlO*{XKyx~l$@Bc}s;W*M^c;i1;3Z~$nus2x zX}Uh|GK!;R?)`*HDI3S}&7vsY!lPDgQWV8IbzOfK1i?397;a5=STi$~WqGcy>lc{$ zoKos;nx=o>t7BU%msUEf!!XrRFP;`v}mKsiUPC_U;Cm|G_BW4Ds r%xorU5g)`!y|I3*Y)ox{Fw_45_+|PU{kE;K00000NkvXXu0mjfhjh!b literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_disabled_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_disabled_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..bbcde39cf0cdeb33a2d698be676aa1219dddcb9d GIT binary patch literal 1927 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 IM6N<$g0wR>+yDRo literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_normal_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_normal_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..67f263c80e4c4e74dc4218338b3dbf576869f718 GIT binary patch literal 2185 zcmV;42zK|0P)^EyWsDw-0fOL91be?f@xg6>8LF9>Ed2k-CDlB!o%Vi*e{Y>Ozcm&sO_ zF?uitK`yQ3qO=3RvjFr=&9a6t5$yF!0vi(nBqrb-x)Ot`N4@C#>X$Ku0)`%WXPk2i zAQ>6X`)5Ul{OU&?6Jj|EA+el*96e-0Oh$9Z#CjA$VmS&Su^fevSdKzSEJqT9=PT&Lj3dzbpLJ#624Z5)#Kp0;TAaNe9q85{L+3zUw;MQ z9MP5|(3Myr$|M#sJ%qOMO4M)M3TeV5g#Pgyy0&Zt*ZUSz#NRoI$l;gap1%myKU~|l z{tSTgh6RWm{wE?w4w_vaDFUW;OqeL4cHP5}CQO1J3gY5pkEQ~cF8Ja;1o!Schiu#Z^e*tU%dSx7MERZHG_yQXBuopT zU@w8^j=NLaYU|mo?X^%4p_l$<*yo%(FLj9~qnBwRlxJQG!RbmnQ|>TD4mBIL1y4C_ z?(%$>Mv9DSA+%rh5yQ4voqI?|IrU#aOB(hGGTrkr+L;zYW;fooCQqG_^BArsptk!B z`?PQS(wYE`~Jzs-cUKOCfse z0RXD+JbIq_L)LRh4HHn(G#MpLlffKiBQKg*!qjoXuAPq}**P%h%OpE$?|T3?PesP| z?ptpMv)iF{2jKt3kF$;|lF`G|5NbW$@ULHC_Pk003e|B`TLJ zL*=)YL-n=7w|XhmwsU5dMv92(bH|C+vuL|#2`aw!Z8&dQ2*Kfm=&gr${lnmK1zd?i zaF+v&K@SCS;b%WWvco^Kp=PN5wn1(6P_S=}VH$bL3w#`$4`iHioedB$7Q+R0-=gz>tVYOjj-LJNwbk@fK0D&iWB6jo*^NS{V zXX%Yj!F_w6`pz5n*{Z5hw{aU>pI=~6Riw}g_DRSjJLG9IAzwWeVr@Odaka3y%VBf5 zGPIRYvuZsAw+Fq??kQA>#3H7L(B9aD^4so0*=KJ8lS{!B1+qpw!wQ`Ku|P69=5!FPBTi!#+KePtWG5h+L@eEI8; zYIEOPV!#+&^S%fG=>6-Tp!$9JDvuPQyoWIO{4>x3T>~d5bE59St;4?ugfUcpV=3er zAA@r2O$45NEZ-%PB9r$JYT*$48`eM%1ylRPYA@rgsbJ^=rQHMG2I3@~j`t5jQ$nw9Get7Q7|gaWngJoI1>xUR!iUIA(RBrr)r zvf~1}fB!f_2VN-ne`!XGTFqhEqE^-KgKzC}lwNZkTyy6`o_Q_A+6I6zFuM$UV^d#4 zO@n&=EW*vtA@bV45PR!2a7{C-EK-EbUBJLOV#it#JJtfA@2L!8MJ1SA3g|lYXarh! z09>cgjb(*h-k*rmbEnB5^z?pWISL`M9EFfrjzUN*CjcnyU>qSvj6Mm8Ym~-|&%Y>V#)Trrq00000 LNkvXXu0mjf#>gXr literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_normal_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_normal_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..96324c52f97f1ca4422697a469ad60f2331e95b4 GIT binary patch literal 2158 zcmV-!2$A=RP)bUEiHF7H8t%qnM`vt zRgjikE*B~)Dzq*mrv!t+%WZ9K&D*wZ>q^u|NU}fQ(9p1X?%cVLs8Cy0^7(ue!t`6- z(9qBeU-s$Gjj2m8z6QZYx)FlrU>N5?^`eWLZvnx+Y{MuI4CVmS|u?G)EyM zn&XjTgiMIa=-x5W9)*x-jzUN@MuSeCC; zyF8Kw)E$^eQ4IWGC&Zp^=!B};TWG{_;H~y_mqxOTY9SO# zN)_!;*L#S%oT&>kTVjv(6;JCmrX>yF__&v64BkH+OSzvchGUOyjh{%` z*Zq?g^lsmR-tAiue(&N<*Gjad-jT4hY|21m>_i(P{k;kIVc`&>g988nLsbn5A441qM2KF{X8uL!uf9ymXWf!NcHzNfy9z`y<;yKEzQJs3T57$ZMF1VeQ#YMws` zeN~N`rI9S6`n_X)buDTS9LDG?zksj(b;uKbL|jfdcRvl@Xaa9CLh_D*F&R3W9aVc? zoOZ^H>>o$)UF8Tn{u*M)(Fr+jM6R>hVXRxM-Y-VdCL^BhkBrxU)%$dOh>+qCFIsDAFH^!x%uRhgaCsuN(C zHy?(1^8o;3Cx5San$znuS`Nt$n$4^R02YlX+Md^b1M8|a5GtmA4ij&)!?Nt7iftiB zXKavTtXmA7JwNuG;f@cazhI&YO+#q8cLjnS@5I`Y*Mq(t-$dmzyOFoxZbe^1?Hp7# z?^SGbHb05L`L_T7#b0;~rVlSwzi5(nnl5z8U%vr{8%Dv=5jXmFJOTgN(;8JpGA(0A zLKcZ2^lk^jT^A8?4Inx+2+8M#G~u77uZY1H_d@cGA%FdbOqED9qIw9$?o05ty$b(d z{|q@00B5A)JxfNtvB+SWV(_fHSNclyNjjf`RF;C`6u?^6sq zt|@(dJLEtB0HCj?i`%ygxdj6h8C_iXYuF?fQ~yIHM6|Pka}~g?Gb! z=*M7E6aXLxCg4ANdfL-6-BrmAstinA&wW1@K=YD%6o2JwNdp+qzOD)7Pd%&Xe{G!# z$xUewVc_j^2zFkGwF^G|*;&7abyXv*s~Tf%n&O|^(jG$p*>*)c)dHtPY;hsvY4Lkb zOM3{#zAK8h9Jsl8e!Bd^*yFqfb?>VtlHJlC!uYkr01$ZV+)cest zWoZwg`5xu1Gw-oi5OodA`gMG#jspM+njVHwPT#VW%hDb~`zJpIp|~X0mi*)Be`edP z)_{!uvK7IOcVNC}DT==M)pVCgvP}9<#}+H9n)fO$E=Syh==;t$Fx0XSq0S3{EKS`} ziX!m#IXIvF7DkUAfpujgDx3FCS%*w=k1Bs*!@LEk{m~%|?%#*t|0ZY2FiC>1{Um(t zC&3$y&{x$!XD@18L>vpM;MB#|md$&Q4~;cyI#H+=RqA+sThA{-9K zFp`WtlHDU27-)z#Hi=`Sz)xLht&RM6bTbn5T#ckbG?s}(@P?+{6Kx)lIe z0O)4WmyjDV01|)+0MP^;=;{p776TZKj)~?dghX=`LZUeeA<-Pi7y~$N+7SvzBjTC3 kT}OAb%0|LbFk{^R0UW7@oESgnfdBvi07*qoM6N<$f*XJO;Q#;t literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_pressed_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_pressed_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e4503128f65435bd0267418758f4ba88529a39d1 GIT binary patch literal 2374 zcmV-M3Ay%(P)?ph6r44QvJ0C7Rc}-8=e1*d4&RzzN~hCx(%oz=}lkdRK!s3f`E71W=U63BY+h z8wT`#2b>;OMPgW*)}1?gdP4aQD9TOI-SPEY^)?l2rN@pt)0#MCfuTsCy>b;7n!V{R z8sgEg%cvg8z|$miJKkHaI@&fBY0;!W^@Oml|GSQ-m3=U^z}vJw;bzh>48{|8AIgxZ zjfGuC^-u~Gizk$2EpR-&*)~-F5Y<6nPiXc(-qBi-N+xVW4T}JZ0BDWQq;Wi*aI{u7 z143v*{ySmOgn3#kPiqOFI67M6<$ngf<}e0(Lx^&b5Q@+l$k2=kmzJJTgib;zLMI^< zp_34b&`AhI=p=+9bfGQVH|i3o#wJv49Ylwoul06p$J@QL43&v;D{BbNNmH=rehF*F zd8pBiM|6zdyN9mleuB4WSHRVYu#_c)s-~9c*KWhU_zK)@Tj+Z3DZKU%F^(UDebJ?u z=U(V*pIh}RxeaSTYjXcsht8zSQKkq<;2|_d9Y_4(r!gi>B)77e^b-$(mtULczWX1X zH&$a`GN0J3_kqe!-dGpSA-8Td&YQ0XU7n}_fnJy>%O<|?F^mZl(WwJue!93ffQ6jD zyn@sGV!?q1vD+76)HeiKo~RIkhA?vF^%y6g3PA47*U{KC>CQuauRGe%od-)^o2V>-h0xu+allPd zk$Kk)ePFb&2X+4T+F_fA*CCjK?vJA8PDqI|Ug6j!)cMQ1DurIq3WBiGO9;0G$ zjK=(Z_`1E7>~EJJ_A`v83Hcs&@-$RU&CwSvLJ{aVVdiH)LKn{Y+7aU4c@#CWzG(Z% zWmiEYir&AM&in5??6{(+9)X5X@83t~cfW})_V_>7d|%VXG9j<j`zv!QI}1yS)Vf`_eD^8#qom%MleK+y|mtwr|s(e=W|Mzv6YY4QQ$lCdqAB z>)U5eJ+1eY>~7nFPVVo0&ujf}00oO6gc`!!#=m2pdRFhY8d*=xqtB3j_}jSKw)on5 zAG}Zc{=0npY94$N^UQMq$Sz+>?q3^%FItpbs5d$}fBX%)z16o*9XFbqN0wq=I47j4 zM7fo%CscL>bNU&WC!d09Y{D2b7L}-ny2QZ7woUBL@1qj+WdHE%a+N4T5_kyBNt20O zaV^&QpUzH_x{}cFVWOz5N#Yz()g)$vpi7 zR6IXj=k+_Si(^M1Av79B6MyI_jB)vSV&`|yllj#XMei@^p)+aHKYoD7ws(l$bQg5b zrVy{izFGekWPbVhVFOqw`|8VN9$VzwXHJzBGS#f) zA+*ju*EhYE{r&SF`?=T7+Lh$i_N~BCvc$itl{|#@1(*1?Kk1-xZtbex*K+fFbt`!Y zjq#Iw+p4Da6a60Vz`nlM?`=J*nnYzQc?fm-kZ;?Xao!*;53gr&E3S+4`k#-sEK$Kq z9zu7Mf9fo9)dGyM<38RmQ40IwF96`Y@&ewj_EME6Dp1Kom|gKQdf%SD9knBNt3d}*mm6cwiQr{jYu(huB&P95mor;cx==7-M`zhe>RDQBU~ zfy0x^vax2&qUOOTiCl97xi?mme&BAjEbpp%feco=+qcqr=U0i{zNl}NjA3BSz8q`z z<&e$bwYBD#UU?pBR6WM{iC{<2yLXaV@;#i@ugRY@8zusqw(~mL=)CV{tkY*;T{s8p zw6jrT$K{_b6NzC=nv!qmx_BS%z*+Sta&NA|efuqR|EDmBsut`52Cd0$-bilqMj-!G z236mHip9~M3!R71AMMM(7Q)kZ0(F%7RVYIoU2(VnnfgYNlX-wI5p-}l2> z%k(~FnR1tr2!bY`yZm>;MDzN+KueeviD9RuJ9oYznl}LX)9Ruec9PE<(C_q{oHx@1 zW>MtSEJO+PoPyUSn%BGCJ9N>YCFjj-0Hy)sfI7e|SCyjbxa6;b+bB2%_t2n~)*6bB s;h>~9JQBlT+@PqBl?^@E|C840{~T1|Y~bMRi2wiq07*qoM6N<$f))Iw9RL6T literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_pressed_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_pressed_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..fb94b7761643268b1bdeb5634006cfb4a1a98090 GIT binary patch literal 2483 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/ic_plusone_medium_off_client.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/ic_plusone_medium_off_client.png new file mode 100644 index 0000000000000000000000000000000000000000..894f1b9f93629961a0a6a5cd7c5182324fe3bda9 GIT binary patch literal 1187 zcmV;U1YG-xP)9{+Q_x+CmGnOKLgZb4bT&8R+OPDSh}nbndyQ-|xA1?mffy z_V$=4il9k%BwcQWB0pct`wQQ6b=40-^RxSv zZ+-@{3p2EQv|^8tbYKz0wzHZ6GjlST44`)A^?J!b&g~#qdQfa;s9#GQe81^H%tNuU z0W#l?!nv0!wyBx98+lx9XX4yBG3ul!{c&Zxm+)_ClzgjgOC$ zfzXF`Dvf6x-_zs+F^8b5%b3Y0b8V=d3?y!LS0q^Pd>cYNAAxxBmHo=w2Izi3*Z&vHQ)|48 znSAkheBXf6=~Qt^cjFSjY3-2e?}13yyIQi?r|(ha(ecB81vqM4Z@^5xSS$vpojDv1 zH5!f5zQP+0Th#?1N=xBpTI7}6&CtLs>Z*(41eEO>9oN<1COcldvTw?)Tx0R6()i|^-~4v z2^v7{xP_D)@9xl*Q6N62PdL6Znt`s1bvGag0&bxcUS!vJTS|_O0#`=vy-Ef`{Ntxq z{Bgs-1z>b^w1*XoMLbGvlarGW2m~O+U+BXoC4Tvi49I<7)J-^Q^msgYgxYvF`ZyUt zoX*iJR_oB3#bPN94qD)(!uP$vZ{W}P_wZw=`yX;d?0htf^r8R&002ovPDHLkV1gls BMi>A9 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/ic_plusone_small_off_client.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/ic_plusone_small_off_client.png new file mode 100644 index 0000000000000000000000000000000000000000..ac777614e66e02ac71c3a18ffab1a69015b5ead9 GIT binary patch literal 841 zcmV-P1GfB$P)+9Iu+(c&XyAYA?oI&0rVPj)MbV#Su2PTzBV5zZ2HHTc-?CdODPp%-B z;hj<`0d2HM-&-N&dVaIeeqfSGc;B~(dTM#(!t{DQ+)Z^@US39$cT~vOeixQ3=2$F> zmBU$ku55eEZiV|rW1*H>4RT>KGc%AHE+ZZeA;G6rA#{^ zjEo=<2oy;C_*UpFJ-ZIS#atBM3;J=Y#g*$pEr(p#@bEC)pZg%S-hMz26l}kOUhS%+a*Xun} zxQkdaSAri)zuym!$5ViI{hxRguE#Y(O8%)YiXS%op-6iu!6qgq+Q-Mo#fwdrq*!|39`Z2mA!j4s&{7qb{I1jkAl*HSv5 zP{tj(2HMm1w5Rm;wq3cjl+wZD`@BuN9(ti?6H@r$3pstC=e+0B=W?ENN&tYMOeWJ; zv$M0N$;nCB%bJ>++F%@0jHhCAbCa|2KXY?)4OXiaLZJ|_g*~l}jSW~?Sph*1fN|Av zNTbns2|sx9Yf*J#9}do1QyZbgoSr*d3kwXz-^V^?}wS084Vd9ACKY( z;c$50X=!N*CMG7FWOQ_NUjil|Sr92185!XXXFqCjaS_JG#wZyc9_HO>KPngu0t+G~ zLqkK!50?W0@b$ET<7N$rRi$7mdI?PLy_i#$vXc-PA1qi%7DP%01_l7Tt4I9@2&G5C zeEt}?ZhsGfrdn__SaZn{8I*A5FxbC7&xPx;r6A9LJV&AF@#Dw9f=J0Dg8{@V7de1* zwG7t%URYmWhe#yC|3^Je5G&r1f#Mf{_f=fSlVO4Hq!QPMQsNh2nK?K($RgRR2ch^C zFrRw^qQL;aXe`)-@OaH7$s@|rm=5Y?b~`0^bDiu9R^p40EK^w|^*tQY_48FupUD_O z{q=Wco7uj(u;YN9w)<&)L5V*O1O5H|l=Sy>b4XhED=*Y+3R6$ohQ679bNW21{K7og zu794f(J48P&*uY!!9a+bME%_ekO*s`&=L!Hwnm$1oYT|511au4&lqq04f z>_I7o-rinHdLQaIr1REwp2N9>(Uw87dfCn=o6HO{+gh?DE|);aVUssK1$%hC-Z-RQ z*U2Hp%G29A`LvDlbnR;05lHdNQxMRqA-ovm5qTa+y?>69uIVPcT>{Up<$3OvlAQuiKQ$SYc{$5y2b5K zp4;*C&Sjq}q4Y@7H=C$r&*&@5o;>$Mx!rE)>guB8p{6|vX(~Dht^qwS*sbz9B(Rjf z#qGq3w;{xagiLnXgi}%Kv!1#1^|a?dys%8ZsgO$cbh%uh)9EPDwYNQmWD?ls&K?cV z=Y%|h5vfd^OG`2*Uf640%-ex z2p?+mwM~UovWLUr02V|_nwy(>fo_$v@oyQVSXm4%)_gMA?zB=NmG~iKTU#3?O-)U_ zK)1?k(52O>_1b5!V6|kl-$|u*U?qN%Bmv7*N*+9TkkP=;YR`W8OnO6N&z6qKv0Vp! z79k|dR7%upH80SFr14>p`gCBs|2ueo`!VB98*l7(U5m`G5M{I3fMqHr4JsAb8vX=J z%_m?wd-!Q;viVW0Dgj6JM_?^Gkq&$65ZKyPJnsutq9_8(R2Ip5|L_aOmhP*)4Xd-` zuo+#8zxrUe7XHe8HOy}>X`sc2z&_Mh(2$LdjjSf?@4>>2Du}Jb-__u40u3;q6T)Nu z25h7cgtM=K@!bPSnJdr8Yzs;FBNi)1o~|1q2FL4h8z-D}A~pdm7vGeD+D9H0B&5Y+ zK}a`Y;k3=q&x74=&r5j!39*zmzJD+YDQVPs`|qZvr>C*;3=xe+^BtS-6glI_z6dWLSRvdH~TM03qcmb!L1~%jI-}7)WAGz-S6o+IH^@x_d{dPkb!PeGR90cl; zzci!R_;ankzFw-Wt%bcVl}a_oX4XrwSd6p%2UoLdTuBY-{Qv*}07*qoM6N<$f@oXY A2LJ#7 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/ic_plusone_tall_off_client.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/ic_plusone_tall_off_client.png new file mode 100644 index 0000000000000000000000000000000000000000..08a4670c4785ec80a0a04637baa44344874f32e2 GIT binary patch literal 1140 zcmV-)1dIELP)0015c1^@s6WDVo4000C#NklJ7h{HV;xBV%*?fyS&5UuGnxz_GVi_-mBEeb_ zJ650+3a-7hv}?Od-`{B|;dsAK>9rTywOLv^*Z%PNp-<24Ir-d&bDn!){r&yS<#HVm z1YvMxWhH90TB$`I_<$Gq+1}n}5Ook=1cO1^+}tE-vBeJX0Wa_aPt0bsX|a&WWGIzN zQ8Jlqu>*X-3;e(nvsf&-jg5_#ocjPj@Wd7u7h6KA0G`;w!U81{i53-rCpJGnFE0dd z{XyQVpOW*vPI7dq$oA6XW$~%Mp+qd!G_v4{&CbqJ*tSg0_fL}jl{N}!u2a%FPcegz zTxUBJg1n!crS?|145O>PNc? zi~sE`-)G(Y;!<%B3VyfLx_JF-N{U{7vx;TaGIzDW6VvPUauKeN&Xg{C?AM*<{tTsD zt2Gl;jzSEEOX0>eS{6L9$;nAYA?~lvQ`qN`gZ#Ju;*)6g)n_TaV&-?b7RhmrD}cPk zpDW32ge-Vs6B82@P+uXt>Y!YVU79|QGskK5%@_G+$LlXpRyuFtyb%tEYYv~VRm8~C zxDGW`0-o6T_&C3tTaggO^dtOm3W^(g-1s~HbEsD#{|8y{#B@3xg+d{|)e7%!;&+ym zM};{fkEs{PSt&+QPaSJ12RyOS(b2tM?vmwr=NJW?LPLstSY*Ky8yOkluT6`=F7tf& zmZCu6wdYAR{k$W zh6!sV@WciO2WjnM7Z+hyJw?uUJIHhS9Qk{%Qgq@bc`m%IlqNlTc(pg0P8K||fq?;O z@*SdxuAjEE8Or5y@;faY3i0ot&@bOhq8^j6tDdCwWeWuYfu;eTm`0+8#*+xz|g`+{>8PVly)2e_=Y?#_zWJSvD%KZhr# z)oRDgW^+{+@hN%nG?#Vv{Hdmq1wZhF2kEw+o*tT;nWDP;ltyM_v+q zzzh7q6Kij8$HR2n(9qCWZ*Om0tyWWuJn#W8@UykG#r_3_!uY0kHa;2v0000Bk%mZw>+oAGZ^W;#A10L0xTk@810~&-1re zEs2N-RaNcWxpU_$>`Q*#VXv*V=hHO(_Vu{;-w_d5Yj0uC@4DT`=-Adm2&=UeEe`YT z#N-I0J5Sy;PV30ZaVlih=&B>V@ZQJM>GWaJF-luh4e6x$ilUc9w3He(IJB&_m+QLzL~H$HmSs=0 z*5f2ec8a3-j)-0XfcO5Ai14yR00V{0p8UrE5XbQ!?LHz3aU4Hxey!_zW5`_d7$jsm zonFLVE(B(F`}^ZK-XS6j03vcuL=NQ5q8KD3gfMEx@!rQ>Hbk`BT#GEP01qA5Hy3qX zpYJkgRs?`!=DN#f5eyQdl-g;oopT=?W;V0^eSe2@E-%aS_INzLIm8cOppZ08pEsc+ zB4>>;SK9p|!Xbq7MD!|6)5je{kci~7x-*EObwu(!e^^!3XCkuhoVz+6k4IYTXCk7V za~}ej=6U{rnf=_+1~9lFGIKo|jqXn-leG}Sx`^nyuCI#72zx@mZtrN$x!hXYgc1XQ zh~#Bi-Ua|7s*0j`@Y;nmBuTOhU>5+&vTPE+>%|(0NPa|HucEmyA#I4r%vOYrF*mX- zd#IF}0Dw};WLfqN0C?~7>2!LNh^jPAAI$Czedb)~zAhrgYj4 zAMD+S(Pxa=AR?Eh>7$;0&iASBjcJ;GZ;ZJi zB4@n!SIV-ypp<&5lzPd`QxReB{Tb)nMF1*I)6J$RE`#1elv0zTDDGKn-}m0XCn9e- z=dL-omoh{&C89sI*1x1_`T|S-7CESn%yy(F0G@~lg%Dy9A!c@6fBG(yg`KsCNR}Bo z^EfeY8c&pvmHj&PKcEw}A_oeY_kLx+VjbpN*RB<|wzkaf?(QvSUa7DPA<*{rw!!QG z+UBq)p8*&h(s$gH08G0cmMzZ literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..58b75bd7deecdb891f150ce93342dd7a61b86a9f GIT binary patch literal 1236 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..7d9ed7834d640951a20c2669f70ce83a29d91784 GIT binary patch literal 1389 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 U{AEGJ9smFU07*qoM6N<$f<(M_o&W#< literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_normal_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_normal_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..f2c3f557179826d9f2fe68945377566e20ebe1c1 GIT binary patch literal 1369 zcmV-f1*ZCmP)zRM$L%&K_h5TK7c}qCM24Whyl?ECZLif zvIvq4kz~TQZets4?bh|a96z)v>)Niax68`1U()2}oO93f{Bxf3oaf$Kgb)mYi2X*J zA^pgp;od=jkVo5zTrn;r-;h!@-gxcB!;&O#z%=qpsH~Vmm`5jnd}!0)u2e#lzgH~Q zWMQThIocSKEM}ZIZv%{h?J_CSnrRq$DFQ&G@h!hX#{x2G_Q^fQ_&Jhyj0?#()Lc!Z z6c*uLvK;5Ex!5N7kz55JCFT+BW+R8r1!W%myH z|7ifgTfGYG_7M{S7KNy#KFYSd3PKP(`$IyXh(zc-{CUiZOzFn0R!n8Yk`VWj0L)MjBiL=l+>lrj(tEKkeqFd~T~fLQkR8!g2%b3wgI*HY z{FO{T_znKreOBCv+OcwT=+`rZFGoYi@xVhAtzDncFR3q6eC>PnnLSs#LuFA%WVO_^RlECT?tA8#V5)#9zA)t)+=TY!!r_-RYm( z>Q_-v%l(9Y`z7Awm@$jWyI)dJ0EfoAmfXgFaEXp4o|aIw51inj<)^(qP; zdji#0LFD>X^!8S|PaVho_)=uI2es74#P|2p^u|kQHyf>*Oo^q#0oZ2>wD zeM)bA9hhdkU-eC(yrvfCgL41~U#_Ql=eE1XQ*8E3q}%LShn8pAO3Jp^V1|M;*KDQt zj|&MR0QB}&THbtx-V5gdaL$>J?D5{U9t*Q??bB!?5n^eWs-pFwsyY5ia~dRxG)4}KLBBURQCSA)IBitV;%;6J bgpmFN5>V=2AhwOzM% zuWSpx4ABS?92z6OfQd7N1T`29kO(FU68#`X6O2J6q686)AQ-|xPy`YTd|?{q48&-H zL7YKkLCAms8Dnd~b{p%-Eld zyWMvW0>-EkCssX*bT_(j?GYmr+BwqbSPuw!CbWB60hd#N*FtU$i97cp>8dB{e zrl1D`v>&XctKk^hr522?t8mk)R4pGv!Aq}_b=w{3N*hO7gaqq;z`uPnp6BL}KW_n= zuZ_#Qwh?ML27r6|)3~3Uj(zMnBqeR%T>>nZR24GQ$Ysyrz$4>+xbm|0G_UuaV3oXjkKMrHB7)SoRg-Q1dO(WXUjOJ^# zLIbe6kH|8kmwv>>74Oq^>`(k(Zz6KOiJV8Lp?7u?sM(9+@lyK1%9O((ov=LEWmgVm zD?X#^@4x6eeiWml9pBcCM9w!MDGIl5{SMjTjK@b?n&YJ;G%apxS}+#?wWO5N<*Nr@ zNDLC$6DE>9Ay#JR>VLmxmOxId-s|PmlTEUjqck8}ty(;q$hor!P2=K+?=X7l$0(lI z^ioSoxvhF9aAS44uYy@2X+8Z4T}Nwe!8zsexGi+@1n1veMC9ygAVyRzDMc+Q#a2+% zqpiQNydruqK(MxkjzhnowOzt~=U8lo#pF((N&Bw{F*-WX{B2x#cQNIw){|8}#%jux zup}f{TZ3=Qm)Hu6DR}uc9Fry|^n~Yy7in3wjL?Y&jP@XH>(@}Wa&6pyz0Ay(Q+Jpy ztzg~vw60%`>~vB7$vPaB4<D)m^auc5$B&}72jl+hC1tjpy2F$Zq3c}U z{uKc3su{?=96cmerRa?%NU92e5e%3~*(Xd1iC$+x^f1cuRL{N-=A zAUjC4?JKa%Im>I*%N}T{VMIcin@Mn}-n&5k7O8_5=G7 zp%7&&*P?j5>ExaO(?XOy59Ob3Ah3TQ9Y6m>xbYOe%^Pm`b3Kf@cLKRHp2hX>V@VS& z-LN#kB~>MF<}C7N&H`OW4+aprj_hLqZzwOJ#kAlwZx7cJ9bx9Rk>tY&Zx(7hGB@hy1Lz@XosGNs(`&0|4=~yVIX>w zF=H#JUl{pQO(sGTLVzSC)R>gq8$(@#34D@zLI~+U9+#x^lrsux00000NkvXXu0mjf DUT%3P literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_pressed_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_pressed_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..dd74fe8761cc34160530ca3d1781ccd543dcb6af GIT binary patch literal 1465 zcmV;q1xEUbP)2Hx1}wl zlvklr3rH%4S3^oLs6>Pyh)Ogu5rhbeJPaB|(uj{hh+hm61Aagw)DIY<5L2Qg5Fuy~ z8e(e#1VjjEt1YDz%67Zmd0aotcDvgr>}>6}@t15mIrq*z=fC&dbEmTxDJ9(?BcHye z+c>0@h*(48!Wr4XRA3a~>)qHACItKqRAe41uLqDIqe2=N&X@qq29&;u@1C)N6Pbs~ zf0rN?h|WZR5&=%Evm>!b1D`_w648o+6FXYOklWfK0g-qAa@C(!jBSZdZtgo2Ra(u# zQ}WL%dtw616(CxLL>IPUOGW+bYBADIEfEgF5=yaU%Tli*?1;?=&eX(}H5-X-rPxfw zU|W{3JE_F|ab0wZ0;KG>e-Fq3H6sIp|AnL)TF+hX4v{q&&tnTv3n!xt9|it25b<@y zuDVLgo}Jj&E+@-vl%xpp%w2@ObPeHeOKBDCo=9xN+4Zu7r5zEC5|c8ewE}utU39S&m&-1AzL#B!sTJan~)b zgednF03f_NB5O#;4pL&Bt8}h~0B`U8)9G%Fw1lFU+O*Lv_lEH^isCy!yBs{lY9Ux;_f z()bRV2W|RHtjiY&m+tB~faXCNk&7~Pn42)1pZ)6po#IM}XWnA;mp35mYH0al2WDkC*mksC+5aWJ zjoVNsPC{g4;#;?g;HK5l_Gp?Vm`<@IoLZi_PvKiv0!?=azViy^uczWf0N8c41WR7S zJpB`ZQ`IuE+B&qRS%T>lOJYJ)6@97m%^F9_kbyg0_cg+Vc5DG741mbY>bkEB5)z_} z9*Y=~4G_0SbcMWg8@r|&OcPmOmx#-rV@l|*m|a>cn$>fEj|Y*RgK_dlWT-hImpze? z5c~Q+&cX)N$wlbP*MidZQ2L9nLQ{a2&p$~l%DW)psulY9ef%G6M=h9$cgZreqFES6 z%CIh-N8Y{#x(_vf9G*E(g3nKI)9UD^*c&7)MBchd@a>g&=Rbq?$b8g-3Fs>~w6))E zz&igM;qSk}{N;Fuik58LZHR_JxNJY+vi+c{PDN5RXbSZD({6i`_pD`E$cCFq8}42i zFmDy8wntJqqrR*1;2qnZ%%QXq6DO;d_Qiv27nK?Y6x z%=kgRSTP}J6H*NnfFmR?&HLpo!}_ZIS(Uy<2xMNG*VKfF6;drhwhE~P@`+TjbXB#| zRn=-gPzqw>#O?$hIc0Mq($HUMJycT<44`99Qc8%=IXYS7eO<-k;*ss+ky88%NIv!_ TQCpeo00000NkvXXu0mjfmxi&} literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_pressed_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_pressed_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..b7dc7aac7eb599813ab285e7216a19b39706f628 GIT binary patch literal 1521 zcmV?Odxn={Ml|MF+>v+O}sbJs1UsHMnmGAFU-&fhh=r z2%3R$>DIM7>$?7)_MG#5UbJU)UENsQxo+`EPSU*ZX};$<-}}Aq`OLBeE>EAu&yk(nxO)i0C4T3laOy#C)&d~k5o=my6RF0i9YS~CpVR5MWygI4FZ7S}~p zaA>l1P$Ss7nvr#Z|AjOggr#qJF!&{oJG@zT?D1NpRx2;q1;SNkk+H00A1)VOwZ>SY@ zht{zU+3{|-+yCWgYWAzU>Evii(=NnRwSPp3j;6E%06ZVEJ0*^gl@bBeDP*IK=a27j z`51t~a5hu!%NvZH{v$O502~1Zx?G-m###z>33+j|-63&=Xq2&x&S<6oLQGYsR6_@V z9d1#w@npq{Z(TyRIz$lwEF2+ziQ_B%48V;eg6MsQ~~P zozYp1E||4Op)MgKikdTjA8nUi)gHH0nuT+bT!vOG^>$ehhMsK+eeqcZrt%?M`>O-@*~{L_o5QrnJH*w`UWT{}(tyT5Y_rp-NaT7j@MU%77DB z;!_{@_%`hETC9DYPEUs{i02}?j6>kKqwTVDI&T=qe~!nhC4&ZGE6{*~m?%*C#w8`% z8<4C$eo1l(gnP5gtnBzXbpUQrtppv=>7R048#V-hWw% zE|*6`Dmw!(qU6;PC9eX&w+Dl^lARe9Zvf43nr9=JvuQOJ&4%?_<%r}Ay-gNGfq$5i z#ir3z^22?;z)rU)IYo|pf4AHJ>P2PJ^qXN;YdDpo=FmFQE<4`Y<@RTEYP@z)nH-MI z7XbhhSwnyQk`le7DNq{88M@BECQIFLqfwKPjDA0e_6H@~QukXp zLIM)c4@cE(R&SymVmNE)zr>3@)?Tm0`t~ljmtUkoe`}}9lhG;t==a%~+Gs9~nzPn> z*W${lUVm_#Q?$I?A-nc(kZeQYZ2Gr^mXGHtwF)3zE>S!bvOBCiA$^yXs96+O0yPU! z^3-_cM`iL@hwON6lTGe)h?apam)GnYtL4A>JCpi8lFL?Rv__+@I#QsFow=7z zow=7z@dWTmJTDL+snM!i-<3qedM$$iQ!5xcOJUu-X?S00000NkvXXu0mjf&v41S literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_disabled_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_disabled_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..efdfe2e616190f7fbe6461716c87103a8ce0805d GIT binary patch literal 1309 zcmV+&1>*XNP)Zhf2Q z`TIvT$PEUAxZm%O4|^PM3lYI+G}^p*^X7NhvEVTc_QqO!E=|)P-_7veob~nf-pb0# z@UX}6wjc>>?G0?}Q_Z$1G%Q)Y_eXPTogn6E5Mo%zP-u>0ful*t!@5QgtYZYhIz|wz zV>IPq3sKi~JRXlPc<+};W&rd~8xa}Cal95q(Z2_E-IKDTK}FT$)mci z)2gbjkX!-)t@XMw=4li~FGVEecr9q{60NnDs;c_j81rkEWlxMT!z4*Id%fOIBJv6V z>bky2QU$Tv(@L<(O!^D};yC_$woOEQ9LJBQU#qHGZgZ``Hmw93kH;6V9jm-j%I$2A z<9Jg=*83w>9 zrK%>I!2W3^nAUo8dhDG0WS-f?_OGVK;c&P*7!1B~&h^@i<)qL`ury7dPhB3#(?wBS zo^2`u*7~JVYD`kqb$!Y? zcL9J-)AY_Xc@8Yj!h&h7%U-W{+gkf^UDqFxe9t+z;@oyf6Oplq{9}yyBTds6I3mvp zcb!&w*klFx1i%xL;=PYaic-ooZ5ar(=fG--BEsPE-acWEMaKw&b&SR*Fat*x2{Wu? zG(Le@*LAq#d&tbwplOxp*VfjGt*xyaN~t61F3YlvA3uJ4Y+w7}y_b!RjRKQ``7HBh zQU;(ur!DYq7yu|{PcW=Exlj>o$@y5R5k{GWHlEK>dh+AAXa TudR@U00000NkvXXu0mjfwo-Io literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_disabled_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_disabled_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..c7650b09e31f1af8aa3832b36295cc4b40ac4ecd GIT binary patch literal 1316 zcmV+<1>5?GP)P_FH55P0^0s0zM?*K))AUA}zYDtPHs1X#r*$?l`oL<RH)c-LTN1onl;*O3#nY8ec$IBFvTuSXE9Wdy-m2Gvzw{Q1sh z5PcA~xTAppfcf$LAHUk1ZBsS<#dcbq^>4|^=(r+)vjBbr;HT>qM#4<5H1f;<5q`q@ z)*H0(z-(-6bXQkbcaPeR!{P?6UhtzM{7W7%>|rfKV2^z)@KzGyu(lBdYZ*bXmJtMN z8Fg{kTsY@CWm%r{-Y+q8TsJlm?RGky%}%E?Sk%17jfDu7W!ZV>+=`U)&nSxSIp<7O zRi85RdjKG%+*V3G=yW>Ih$sZ)4QT8V^E_X+)~-q^e@~L+FRgWIjM?dSySItxIRH54 zmH~($R&yE&X00_=0270L*;KdoP>J7icILGxx_u>747-^&z6ClOl5n)SJ@u19X$Za5y|u*MW$Naj}w8 zRt@Jn_B0YqO1U#BTWc@w)otAOVO?XIrq>69!4Fkcb(`37TxcX%9LJA{=m`KY^T{mB zE={*Hv+&-ZA);q-9N()OgP9F8C&67FjHYoICrPrNW!X2({JynzB~8<=QtA;itMRHU zyWQ?u-JvA#`ZNxlrIb~_-@jd!<&w2_34pGu>M}F;FcS2aX|b%eNuKB5PF^#!0f4eB zua{-%0l*lurnP=&f1qr_!ctRF6g`Qe=m`J}27}1~glB_gW){qx%)Wmj+@#NgyjAJh&g!o4Y;a=50us3rFrj*KwXa@ki z_osJvcUPEs&l^&+Ec=XzDr3yuc?}JWnERBNB*~pD%dRo=N$1?9G)>P+DIZ8F{}VzC znOQpLPFQQt0g!PV--BEtdH#uW?qg;?VXeJl?Z{gaQAtEkwbon4 zn8yfD!z_eGaTpQ#BuVZAxX;Wq{?(a;5H@7z4~K>25{Za|%R78RR=i~d!CHnuI1IE2 z3M;H-DAYZH$sQny8@PJm&6{)pR<8oU>7zE|P~rMqc>O7Hb1lV%D}7LSn)XOw2Da|j zKH;;MB7Fe8ecA(u3j;_23}!0Bd818)KL=|eL9muVJo?w07kneV8+%t9{QbV4^Gkac aGyM5?GP)P_FH55P0^0s0zM?*K))AUA}zYDtPHs1X#r*$?l`oL<RH)c-LTN1onl;*O3#nY8ec$IBFvTuSXE9Wdy-m2Gvzw{Q1sh z5PcA~xTAppfcf$LAHUk1ZBsS<#dcbq^>4|^=(r+)vjBbr;HT>qM#4<5H1f;<5q`q@ z)*H0(z-(-6bXQkbcaPeR!{P?6UhtzM{7W7%>|rfKV2^z)@KzGyu(lBdYZ*bXmJtMN z8Fg{kTsY@CWm%r{-Y+q8TsJlm?RGky%}%E?Sk%17jfDu7W!ZV>+=`U)&nSxSIp<7O zRi85RdjKG%+*V3G=yW>Ih$sZ)4QT8V^E_X+)~-q^e@~L+FRgWIjM?dSySItxIRH54 zmH~($R&yE&X00_=0270L*;KdoP>J7icILGxx_u>747-^&z6ClOl5n)SJ@u19X$Za5y|u*MW$Naj}w8 zRt@Jn_B0YqO1U#BTWc@w)otAOVO?XIrq>69!4Fkcb(`37TxcX%9LJA{=m`KY^T{mB zE={*Hv+&-ZA);q-9N()OgP9F8C&67FjHYoICrPrNW!X2({JynzB~8<=QtA;itMRHU zyWQ?u-JvA#`ZNxlrIb~_-@jd!<&w2_34pGu>M}F;FcS2aX|b%eNuKB5PF^#!0f4eB zua{-%0l*lurnP=&f1qr_!ctRF6g`Qe=m`J}27}1~glB_gW){qx%)Wmj+@#NgyjAJh&g!o4Y;a=50us3rFrj*KwXa@ki z_osJvcUPEs&l^&+Ec=XzDr3yuc?}JWnERBNB*~pD%dRo=N$1?9G)>P+DIZ8F{}VzC znOQpLPFQQt0g!PV--BEtdH#uW?qg;?VXeJl?Z{gaQAtEkwbon4 zn8yfD!z_eGaTpQ#BuVZAxX;Wq{?(a;5H@7z4~K>25{Za|%R78RR=i~d!CHnuI1IE2 z3M;H-DAYZH$sQny8@PJm&6{)pR<8oU>7zE|P~rMqc>O7Hb1lV%D}7LSn)XOw2Da|j zKH;;MB7Fe8ecA(u3j;_23}!0Bd818)KL=|eL9muVJo?w07kneV8+%t9{QbV4^Gkac aGyM*XNP)Zhf2Q z`TIvT$PEUAxZm%O4|^PM3lYI+G}^p*^X7NhvEVTc_QqO!E=|)P-_7veob~nf-pb0# z@UX}6wjc>>?G0?}Q_Z$1G%Q)Y_eXPTogn6E5Mo%zP-u>0ful*t!@5QgtYZYhIz|wz zV>IPq3sKi~JRXlPc<+};W&rd~8xa}Cal95q(Z2_E-IKDTK}FT$)mci z)2gbjkX!-)t@XMw=4li~FGVEecr9q{60NnDs;c_j81rkEWlxMT!z4*Id%fOIBJv6V z>bky2QU$Tv(@L<(O!^D};yC_$woOEQ9LJBQU#qHGZgZ``Hmw93kH;6V9jm-j%I$2A z<9Jg=*83w>9 zrK%>I!2W3^nAUo8dhDG0WS-f?_OGVK;c&P*7!1B~&h^@i<)qL`ury7dPhB3#(?wBS zo^2`u*7~JVYD`kqb$!Y? zcL9J-)AY_Xc@8Yj!h&h7%U-W{+gkf^UDqFxe9t+z;@oyf6Oplq{9}yyBTds6I3mvp zcb!&w*klFx1i%xL;=PYaic-ooZ5ar(=fG--BEsPE-acWEMaKw&b&SR*Fat*x2{Wu? zG(Le@*LAq#d&tbwplOxp*VfjGt*xyaN~t61F3YlvA3uJ4Y+w7}y_b!RjRKQ``7HBh zQU;(ur!DYq7yu|{PcW=Exlj>o$@y5R5k{GWHlEK>dh+AAXa TudR@U00000NkvXXu0mjfwo-Io literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..8c76283e50de58d0b3f7c40ee117ac653830fde4 GIT binary patch literal 1461 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 Ri!uNJ002ovPDHLkV1k=9yyXA@ literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_normal_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_normal_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..34957fad5f97e36198a103b14a71f25cfa01220b GIT binary patch literal 1455 zcmV;g1yK5lP)f z<=U$|tSO8wZnt}u%jLTL1~`@$ot>SyT(16hqfc?W-Lru8fcD>ZnG_|fuIrW?ia zdeUG(hCD&f$n=oM1OpPW56d=$U|EI`EXxprWf`gVVQHZSgS79fqpR^S>iJgmuFG)M z>9VbS6yE1wB4_k1nVNRUkrBZ{_1_WLvVo$fX5*PN57pns#qFC3Hy#GSHSKX+k4__Z z%vdB##=av%64N0uR9DM|Rm*YDo=f2qPm@zV3j4%Kl)b-#+={U=o9}BeqER7M1~4U< z8t~J${xgsy@~1wQ&?n{O;F&u=_MqzozFKc)DnU1<1Z&@0hY^V&*=)#pc}e~DiIcDv zmjDp{s}Um-F*BV2lY&K?PXb^>qiDgulMN(^ym5EM?hOMyDg-l&DZ!-N-1zW ztZq+iB8L-;GvCZ~0!#{Kzx$r}eQ@`#q%t0eud4h(84l(Q{nTp2Q$ z63jVy3VGuu01!TYluJ9eC-fVt!sXu%kXtbp&z$)w$4~=pD6KvWMKR;bkilG?Ez68t z^a1CVyhGRF-wAxVj%Z6W`43J->+B?0y9-N^o6^NgQx+wH>&NuQNOtB^w&WAK{``Zk zBZtsC+VO8%OSGjK$ztK=P2V8f9dUc5)rarxH{#E#zYPH2yVXcm8vvy>%dnN*WY)Do zNrrZ^5_#h%kT*US9#1#?+TARHoEUWtRYhs_C5`Z}aDWJpz0fB|54Mt#L{Fc>P*u*o z_a-A3eTbzfRxR2_lrnn#wz#dYrW)mJOTwzMdW-wQtwBLXPwNd$L%q<7WAelCw(zl| zw7j-}=&2I`NLDMh5vB1tvfUdk}f-F{7bOTMdn6WVG-pY zts%H)HyuCzK&0t7{tauc^cNH{?9TBNOn(yR{SPHokb?9uwGWeQHVS9Vq;SSe&@{AA z5JS_D9gc)NC&(O`J4>`!M98}Vh&YvH2*I+9ly6`P1}u_TVOd7XH!u}N5v#7B=}CiB zRid$V>((7rRaH(|mIvhPw1GeXkH^#BZuA+tt{e6B^*czBu6h#02IThAFX&qgAOa{? zHHyfWO^81S%R+=;S%zd721rsuY?KB^?#hOE-|Od`l(P&&`Ul^4tTdn(syP4v002ov JPDHLkV1i_gvCjYi literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_pressed_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_pressed_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e923ee9c75f4489043a6b4fed4640df5e87a080a GIT binary patch literal 1556 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 VbtNd^K8yeW002ovPDHLkV1m!s2vh(7 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/ic_plusone_medium_off_client.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/ic_plusone_medium_off_client.png new file mode 100644 index 0000000000000000000000000000000000000000..d7e57771539cfe1787307ad31383be7da6a06f25 GIT binary patch literal 751 zcmVms|!kZ9i2MRVa4mTXKz1~NpNtYKrc zv*~`Exw#)6H}?y}eLLTG?BHmJtZZF;81M6(=l#6rdEfIg0YHSq;RnHBFdPU3&<*IK zlWq|Tg=Q2*LAhK;qtWOJbkRw-@caE*yzP^r9HiPus8>p`)5V?K<;o)-z+jobdg|={bczEW}ExcYYl+gj~dq3gm=tv%t z^vlOmo|&1%@$s>IxL7RyHnE92avrlh-C}KR4LkZ3$l|QyeOtT}(ea_S@$T#tDq1tnIn3(l7Aq?&`a?ZXZL`Sb zat0~A1Cg--6xBpq{3Oa~zpQP+G2`4{{zmoAFm6^)w{W}N&Ek<>B<=5z2?n5koI_Oq z8mgf$$mjFOX0sjPr^K@p9Uqjx9G}d$7GPFSw{SY0sPBZaH~Sp1C%2(o>61m}ubZ+> znM~%FP-GV8TxNB2i>0L{`IdZxnznDWGrP5kbUJ-1N~KcAcxwS>b#x1d!+}&PC1EiB zaICo{`u-<8ZX@?6@GS5SG0W2}78e&0cg|zSGKKBw2_z@)Vf)rlvlEwlWlmMqe*)dY zZnq<@UmBWz+PT_Vt%mQ_ihd6~Z7xDToC*JDB$LTAhi)t(fJP+ ze7n?xnAKwB&WcDR0=k9E<(ghzUY3D)Jl=+uPRRxAy5@h%{S9={Nw?tNBK>oivDs{z h)oMjIpo>nre*ogX(Apy{0Q&#{002ovPDHLkV1itxaPt5F literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/ic_plusone_small_off_client.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/ic_plusone_small_off_client.png new file mode 100644 index 0000000000000000000000000000000000000000..af301c2dc93b5018231277271f661d1922dc30a1 GIT binary patch literal 581 zcmV-L0=oT)P)wC6h^%7H813N@A+}`6G%GN8zj`#7P{-`6u|y)q#xM zERjfHYiU6Q)oN8pwHxQ5Ke#UHew3-xJ@vMCdu{%+UDW%_5NqoQ*upXR}bRO^QZW`YKLPrh$9>-450JiRejxV)uLc zuDd44%|fA&nAU7IVXr(Fja#2Sh&>(#4H%Zwcl{Z;Ss)NVY5g1cJ0J8%(@-y;Lh;-& z@X%WrhA{vw!?3(wuMcG8W`4ha=cj)O_J$;G@vGs&^tNL2>^OMxJ#<|^5S(+6n}x&S z<$OLbCTf}{UeX}_-W2rJ*CP90NS;ciKyDU`#SR67!BwBnx9fosu}e;GO%MM8T$_$j Tx_L`a00000NkvXXu0mjfwwevn literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/ic_plusone_standard_off_client.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/ic_plusone_standard_off_client.png new file mode 100644 index 0000000000000000000000000000000000000000..f43e965fb8d333155a400f18362bd9d98cc44679 GIT binary patch literal 996 zcmVaL=^FbXr&XSC5n6_OSYHc;8SZZw+ z8);Hn+UCaOCO7vcY4e_(q-p7Q=Q-WIZQ9&Y(NF^)2yq0_&h;QtrP%gb2KrlH+9XG!G- zU8p5>xd&)O&4l(CIkC~v(F*-|@!cD_#$-$dwQ>pJvj?SE=+w_Bq!Kdw7;*_6%85O) zPrI6IHVfgz*~rMqs#qp1ZB3{s)Az)hHRGShb@_*qO&W+?JH56FHg%ay2EvK6;o)H^ zmeHcJaXke+W_6_9ZQqnPBIx*jQ=9R^iO`vSb$izC`h|rB2q(^lhK7XLE~F;BNT<_v z(6okH_R5a*KW=Tx8=(lXjcxDGAC`MK^Xj=JW_SJk{5*scXM=--QcQbzN7`;A^y^Qn zBYf>{m~Vu{Hnk5u1JAE6l__R-eJYiLaN^AEc1y9~(Qjakzmdi!hG!U3`g$AkV)oW& z>!F%P1RdYWoP^eDSHV0eJMLq#InUYA3=ZTf#!BW5wjI*KZ8m( zBQLOH{js7rc3a=+F5g&dirMvL7zTtBXZ`*Cd@&YA;{HvjmyaXVw%;1DdbI`B|2t14 z65E2rw#rR0yIj|GkQ3|c>*MCAYqc7+S93 znx;up!U*^*F{SlKXg-gXZ3jA5w#rR0yPRCeiMd=Z9*f1KDM7QR-8{dxfscKQ=u4NC ze=O$yv&+eaoS4(;;+%p8rVnW(A?;lx>IXJ@4vSLJa)YfQ!_bY7PI zUU|&S9@vG@m6LUOGYE&n=<4b!(NYG)3xG6j1ns$;I7&!NY5Bpn?o%ONNYK;MO&~3JLw97ZvtGB6?Ac2oq5ZV=!itNCS~%(PWId zd+&6cZM*w%w>$TPCVo55S-b3_rJMJ~_Tq!w=Zxn*AJ221voQcH7!2O``~9n4uNSQZ z)l9W-ZEZ0oNs>)b6y)=H@IXsJHB;^6z&sw0UMv<-C={@yY-wo;dMbt3gbksm{Rj?rVddOG6X6#_(32{1xm;614s3C85pwTo#NLmfTrOjC za}#O%m=KV!9Y;B(ia6Ofs|Y!;g@px3SKCnHTcqo{pj0Yh{n>z!S$lljh+6^Wqr6t; zBnRelxe&a02H9-Z%=d4V*6KKf3~#+{>vf|2iXb$6&uG{E=BtGq*!=uF0v8TLOD2)Y zWDN8~+<2)LkDAu@g4}b`^c?7HgM7Umfh$Ku&U*9x4{~60b8{kb{Hxvk0X0@>t$|Kq zUAM@MQ>N$W+hG*6G!!1UT7(?f?Ch*atn_st9SK3xG(q&!2Yz;rBJW=|Vtax9^R*L? zo+(blg8s^XMe5198|1*8PA9?-dqr}o`vgKG53u%p5K`AM6lI?{OzCub&r~ldD!6*l z)~;7Y>dCnq(rDhDAO|)*J&h!vSXEM=KN|fl_nn8j;xn!97ZRj) zvoa?+u&Jpjg!!$m@EuV4FN?1u(U*_J{UOc`AEWW*AC|t@YRG|2PEKO|)f1HTY~`%* zTb(HQenRPK=Q0PN+_{KEBGI&v1MNtLMk57ORW+co_B)j@WMY1=X}wtphr_fZ88$OB z^M->+B(m*8v~7v8*Fr>90!=4DHB;^6!04wgA78fd@o{~0bQG-w)l9YXZ|v+3kR=|c T-@3J=00000NkvXXu0mjfqS|zE literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..9044a118af72c90631cdf1edac8275078e19d3d9 GIT binary patch literal 2438 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 ZLN7j_zEMK+un{~`fUTt?SV!`|^dFvJZ!-V@ literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e94a49b0ae8f052d08df086f018b3c2477803246 GIT binary patch literal 2457 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e94a49b0ae8f052d08df086f018b3c2477803246 GIT binary patch literal 2457 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..9044a118af72c90631cdf1edac8275078e19d3d9 GIT binary patch literal 2438 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 ZLN7j_zEMK+un{~`fUTt?SV!`|^dFvJZ!-V@ literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..bfe4f04639ca1e4412ef1cacd6e8099c55a41dad GIT binary patch literal 2886 zcmY+Gc{~&TAIFE8VP>=#CWdcTk%=Nlm@#LL90|E|<*3FsbL`776*`c+P;%u+k=(Zk zQ?ca86{3(c7JmC3e|&$R$K(BZKR$oG->=X6@qRvD36>Y}0(|0p002P1*a&CM&hGyX zFo=DZJ_AA733v-@Yy)PWaIhzx{pJlea<~Nm@F)B`IMm+ty#N6C7L9RwHl*yIIgZzn z!(!cs-Yb-izphfM)zxnZ%U78rrE9Um*2pC+6(Ib`!h!)) zc`r<4ft*-Vz7$<77w-#xbE-lIYKOm84w|%DzdVtXlW}XWa$95Bp@LbPGm6o9XFabe z`Zy=*+5oX>LsH4@?%%NJ8*PS8$@MXJ?ix=Bb{U={Rsunofh9flr@^#J-Xz$$R-v}z z>e$afJUD9#>~>`R3Tgb${Qc$dm!x|18q=CDH)BKzDvH%@xq(rgAgSg1Io3{GJ{-6l zKnvGcF+$XCNqE}gwepS&bQM(#zvsn+<#O*)O)sZ1AY3ge;MS-Q=PR9Hot{{tT#qQ{ zR392oFn8pj^0>~GJWht;)F6}64YFj{J>$$p3>K;qOM2F(#-#% z(@bVjEdqQr6;`Sg`+)&$dWFPFgJn)lIR#Q@H>86E$P^&E$~#!-1btNfUaCweBu!M| zz=b8QC4MjKE1Y;`Zj*OBHbb-KdDCp%Hn+^e?#6ZrqkNu9seTB0Y5IBt^_z>l(@qdD z8_b?c%sq{f^=_(Atn&1d)PzNkGk`9A{bHemCD#~62TJ}7zRT$aIg*eHlC$%r8>a&=%SEf6l+Y)fid9-%#F zt?aTuWSrC$mT&m};^32z?CQ0LX2<+@WD)x7@9n`s6tUdl{(H+yDz_t+NA#~Uz&An_ z7j@xmWqD@+t6xNdk11^?h2kb7tI;*s?zX)|R2O3>S(I_uEAl3-oTlo1Iwh{Jm1WYh zYtnM!j7fR((ePL)T#u7ScGL{h2&t1@&ALB11k3JAbqETSEK$?;D6vNe^@gE9Zg*vB zf&^z+I@s_iv?34@OWE}!ji`E$SRB9qXJ#%vOINnB;Md5h6g4jiRGjNu=+@j2#PJ<5 zNLgOUvH&d_SYQPwn|FLu9`oe3HV@dNdR2MU%gadY?cTa4dd^dvS8vMRLV9mCXE9=B zu;Ac)&78M<@b+^Z%;-0Ah=bioa@JB6r&kO-7PeG88?5L6Dwk6+J8c7+@^9j(61R4ZfdcfmwBBDuE~QHXtQ#vqaEYm70`ljD6>8!qTxsZrW3$A%&ELn{5JuVTq7 zQ&ZYh;{~*UdC{9y6dSGpl&c?Sgpv-=)?%K`^%LEp-UKGJ=Z?75)>Kf7w=uf3VFyL? zpU1G`C?2lgZxY>d>7~HTZSRH{0i$k?~XB#47j=K=u+{K z3~m~=8S{`a54WMOuO7l~MzHxvUPA1-P<%g(jtw2IU>6F%X8w>BrG^%|VqwM?JL694 zu4?Fb)%$&^Q+dKQk9_W)=ZZ!1FX#N5vnRe@S0#RXvY{995|k00zrt=bf^!qR;iRxTO;HFd^)E>KS+m5yDvdn zI;1F8se&3b5%wmtoc7@rTvfc4DItZOadoun7tn{>fVP4iT8Zre1>5>O`3O>wns7H1^_GGk z;=|CqSV9Ep%rM*GNH7~mbd^#RQ<2lksUXbCFiPrf)3G8vR9BM-8X9pnpd53TOACaE zO**K{B>;WJPA8I*=aP<-v( zcySkwq}kJH53@glJOIz&RcrC|?Ew5S>>LHp4G;#9D-#QFfpJ&yC#iDO?6G)=>ug;f zGHwBmr;kIlIS6asWxWIWU!a(UEU}+4|8JmRX}3||2#yCul`28 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_focus_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_focus_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..876884fad79ef8a0639fadc0239705895262a11a GIT binary patch literal 2908 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_normal_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_normal_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..b3e6dd5b40d30c6ffffea2f3b703cdbba33b644d GIT binary patch literal 2847 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d182b5e2c34820b0f2c383ec5fd5e16e6750498e GIT binary patch literal 2569 zcmZ8j2{hE(A0ItMiVR|SmP|zRNMme0+iU!YFmGfgk$o&7OUXW#UScrFWJ`p~_R~<9 z5o3F$$uj8K=E+v}B}Q3lklr}w|IYcJ_dVx(zvq6>_kQpF-t+n1&rQN&E(iS7y>zxw6A=+o!wNPuhIfI zj|J1T1a96f7=KvuN2r{ruy#T)?@33 zGQv|pn)*nZx*dI(q2xW6?@YSLW@NT!EzTnLen4J}Hdv;|eUIuGL7|?4{6QCgU7ycN zG~nB?O3F+O;BV^_Mjw2KiWe&K7Cio2pC}^kks=OaXi^S|^lEHc=+q!i|#G`4;!cM zAI|dRBB9CvPT}kOGl!AzSAfL!HQ6?MC4t;u4K$Gjj)FcUtg2u&y`nF+49oXh`oHI1 z-uQ43Qs8EE{I|(}UHhdZVEHzV79UuU{{LDVS!E85Fv483u?Bn@bP%-x!8FNA2y}id zG}}|33CsNZb^kM5IWB9tu?2<>x5aCeFUb^C>8ev{qrDAI{6g9O%4lUc9R&RpZGc5%Uida0rGbESrb8pewKO>Sfy-H<4vVzj|9Z&+!4W%NKsp#Mgp6@7WSVn z3T3m|KQw<Ol^pE5^oAqk<*L8V5FOY{EwEZ=eQk3+aCLYdn>jAB>N+|+yGU|sz zES3Mtm}~Ku2^Yo3x0dc*@k@8wUKB+M_^qV-moz-vB1;`S zzA;pj9}Z4jZ7xgh%sHEX-iU}~(nbh9IgA2n!XRw@*{nng$uMLZ;`|O<>>IUe;Z8ns zFy(o0IFTnfpQ-8`Cr5Q4FIf#WkL;)8rLQecGlEuW|ik#I=U z(L3==V|qL5cN>m?iOf^0(-xGsiu@%HZk~ijyp4+0x1eA~d+W$w?y7aS ztbUoOQLEOWB>;d2b^LVlRN@)VLA~A+hFLVaCey%2f3`Wcdf7{`_GAJxSEaY1W;zOm zH`LwquEI)v&`N0hK0u? z2|s-)Ler;a<1H?NnVZz%#^;}<)TxfEc#VMFTDo8(F=>a_2A8)9aD+&D<&v3wc5CJG zHYTq$EI;@p;b;Zo4UEl0o*02xC=!}R%=H|xo*(mg?!xcd^%cKYF_)lIUw?DygCej=If8f;zlA0Us3_I^u`C!AO+#Kq9kFLm;<5*1^aDPrcj++7;o_lOz!bHkJq!78hC zabSear?zA@wl^CQvqO60Y>w~4<2SkC276b4-u76rwRJj00gYG2hrlUsU?_M^Z8xRo z18kZR;>4MchzYY_;lEZZ#%l_Ri5*M$%_=U&H(`psbBZR z=f`a49YCsnvvOTOqyiAY5hr%$^NV|=4`+(`?I;uPx5uf8L8QlJ@iD~1q_ff|#| zF&(|0>*H57BF7E-IAuQD$MOzmgK*sQTb4(%NP76_s>^+_0UyJpGZdu=0C+ic=TCKY zoTq(2|1QcgkRhiTobR;$$|0pQWq-vGwDS0-AyzYb$L`}1SJwS&pY27UD)C^WH?zQCng@bFiS7SzqkR*IyGWRmlPC(C@2v(jCIEH%pgeYf^_MB&8V)P_csNz?R?!gNzSoyng& zs$XQ1E_$_a@}usRE)uR6{#5DyoQvyipggEwYK)O2G@aEx_xYvH5HlBv;-J=f7z$uJ z89}l=-&rKHKCK%}Dn2fFO@L43QBGX|JjhUjmB*Y+Gc^C;FUW!z8I*vRnXp2>y|=rz za$GI{f4Os?T#;_+Dse{A8~^(*>~k#HC#G}eT+gtMk*6-Lz6 z-kmH<_>>8rIiJA@RI{-XwvY|WBuss; zJVaLbzh#m^v4ZE19{qWC8_|aKH+EjAB~IOI0J#bw$+mjGN6I(z{&EltQw&grcKzcY DCt%hT literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..47e2aeaf32a15aa78b4fd4edaa6774802d4b33cd GIT binary patch literal 2571 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 D?`GxW literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..47e2aeaf32a15aa78b4fd4edaa6774802d4b33cd GIT binary patch literal 2571 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 D?`GxW literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d182b5e2c34820b0f2c383ec5fd5e16e6750498e GIT binary patch literal 2569 zcmZ8j2{hE(A0ItMiVR|SmP|zRNMme0+iU!YFmGfgk$o&7OUXW#UScrFWJ`p~_R~<9 z5o3F$$uj8K=E+v}B}Q3lklr}w|IYcJ_dVx(zvq6>_kQpF-t+n1&rQN&E(iS7y>zxw6A=+o!wNPuhIfI zj|J1T1a96f7=KvuN2r{ruy#T)?@33 zGQv|pn)*nZx*dI(q2xW6?@YSLW@NT!EzTnLen4J}Hdv;|eUIuGL7|?4{6QCgU7ycN zG~nB?O3F+O;BV^_Mjw2KiWe&K7Cio2pC}^kks=OaXi^S|^lEHc=+q!i|#G`4;!cM zAI|dRBB9CvPT}kOGl!AzSAfL!HQ6?MC4t;u4K$Gjj)FcUtg2u&y`nF+49oXh`oHI1 z-uQ43Qs8EE{I|(}UHhdZVEHzV79UuU{{LDVS!E85Fv483u?Bn@bP%-x!8FNA2y}id zG}}|33CsNZb^kM5IWB9tu?2<>x5aCeFUb^C>8ev{qrDAI{6g9O%4lUc9R&RpZGc5%Uida0rGbESrb8pewKO>Sfy-H<4vVzj|9Z&+!4W%NKsp#Mgp6@7WSVn z3T3m|KQw<Ol^pE5^oAqk<*L8V5FOY{EwEZ=eQk3+aCLYdn>jAB>N+|+yGU|sz zES3Mtm}~Ku2^Yo3x0dc*@k@8wUKB+M_^qV-moz-vB1;`S zzA;pj9}Z4jZ7xgh%sHEX-iU}~(nbh9IgA2n!XRw@*{nng$uMLZ;`|O<>>IUe;Z8ns zFy(o0IFTnfpQ-8`Cr5Q4FIf#WkL;)8rLQecGlEuW|ik#I=U z(L3==V|qL5cN>m?iOf^0(-xGsiu@%HZk~ijyp4+0x1eA~d+W$w?y7aS ztbUoOQLEOWB>;d2b^LVlRN@)VLA~A+hFLVaCey%2f3`Wcdf7{`_GAJxSEaY1W;zOm zH`LwquEI)v&`N0hK0u? z2|s-)Ler;a<1H?NnVZz%#^;}<)TxfEc#VMFTDo8(F=>a_2A8)9aD+&D<&v3wc5CJG zHYTq$EI;@p;b;Zo4UEl0o*02xC=!}R%=H|xo*(mg?!xcd^%cKYF_)lIUw?DygCej=If8f;zlA0Us3_I^u`C!AO+#Kq9kFLm;<5*1^aDPrcj++7;o_lOz!bHkJq!78hC zabSear?zA@wl^CQvqO60Y>w~4<2SkC276b4-u76rwRJj00gYG2hrlUsU?_M^Z8xRo z18kZR;>4MchzYY_;lEZZ#%l_Ri5*M$%_=U&H(`psbBZR z=f`a49YCsnvvOTOqyiAY5hr%$^NV|=4`+(`?I;uPx5uf8L8QlJ@iD~1q_ff|#| zF&(|0>*H57BF7E-IAuQD$MOzmgK*sQTb4(%NP76_s>^+_0UyJpGZdu=0C+ic=TCKY zoTq(2|1QcgkRhiTobR;$$|0pQWq-vGwDS0-AyzYb$L`}1SJwS&pY27UD)C^WH?zQCng@bFiS7SzqkR*IyGWRmlPC(C@2v(jCIEH%pgeYf^_MB&8V)P_csNz?R?!gNzSoyng& zs$XQ1E_$_a@}usRE)uR6{#5DyoQvyipggEwYK)O2G@aEx_xYvH5HlBv;-J=f7z$uJ z89}l=-&rKHKCK%}Dn2fFO@L43QBGX|JjhUjmB*Y+Gc^C;FUW!z8I*vRnXp2>y|=rz za$GI{f4Os?T#;_+Dse{A8~^(*>~k#HC#G}eT+gtMk*6-Lz6 z-kmH<_>>8rIiJA@RI{-XwvY|WBuss; zJVaLbzh#m^v4ZE19{qWC8_|aKH+EjAB~IOI0J#bw$+mjGN6I(z{&EltQw&grcKzcY DCt%hT literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..64e97068740db4eb29c82df7a6292dcaf419e397 GIT binary patch literal 2939 zcmZXWXHXMb7RO@%4FMj6-dg}M(pIHvC?OD#79gO4pbrq~q4y9#z<|=86j4Ar1c-pr z0*Hu8mEMaqX+ba)>2337cfY*7Gv}Ur@0|aK|I9sSez9m{6bqOi3;+OF^!1Qtv^+u! zJJ3bi-kz9dOiT1W2z?BQwn9M;1lpa^Q}3P+0KgRccU(~J>?Y9;Li$K8Okn25cf2R( z$c0Or)TycCQz)Z8C?XulT@VT8LK2-WqyqD*5yjQ3Dr%!$Yl)O|=rGa8KvAx!zC`I98VQyle(6tK+wYsBI`iifrs3-oc$T!b=yJHA=TS5$R8 zyG8F~-FQ!qEie3>=-xt%csB@;i78DFoL=KQYd#V&I1Q9qH@o~F9|kFYId7!^7>|7plG$KyU$E zc2rXIaLvxNUEa`b7^Zb8W`DbL(}c|b%PYNAwfc`%%9cWng?~fi(Pa~I$k*rxrfOx~QUjZwQ5tg&WNnJ4vibl=Ite-hM_sdC zi`ifM`4g5ymxTka#K?#6Wj|}@DWxE7U@j$198#_LUB8Kano2C*V{BNnC|7ukBw)1E zx)E_+O7T}tE@_YBhSdavN~s|rw6U^SZ5XK#XZ;|UJJ|I-@z#y=5YI$@duxH%;C!cC zaPLc&!tz_kwvL1SQ&zGYWhkiA>~9fsvZorPelK`xQg2v5hcVT4)e|E_zFBODb&mPw zATu`5v|eW;Na9A+f5&-1O|e{(7#H^}qT$w_8>2k&XNMr%4aQ^4!?;o1<38q@WOHo+&PHQ>EguI-EE4ND= zV5xP}%9JkQkr&igU4&{a))iI(Q!!3SjBd3omh8HyLsPgcC&Uj&^oi~MqWVFyOmz5) zIM00ra(;$G1HO>)lg#xG@O(tNW0?`?GLK57>8A>IB&!hOaG35OWfF+Jd?44=7@5`@dS2XC^Hbndl!RD49hU}|_N;-(ifNgm#< zX{vwaOhV@hgIqNoezgT_WihhP%}hTYM{P+(mNViIMCB?*_eSLJ zI}bA7&-B`=U!79z1@i+WYOz&kk_0p&cg;cKg&wYohj@M4OzCli^G%|2Q>TF>@j?0V z<)$$6jQsMGOn4OXE7}`X8d}|UvA#VFUWYbC@2qmD9JXIh9K7l!SXK@OpHEC z15neHk1`I#_4BVa&dgAdn^VeA+<^gdw8^$5jXfh3S(2$(vuWJGp6$gk#~%dA)PDL# zIKqQh!OoPolb-gs(6?-*gA()*et9mGC!0pE;);qzo(ePa99XmYNxPIpbu&V4%H;o^(eg(1J0@?|TA`*3b$sdyq zMc)NW3g%u*k#B%M)-ndLsfz%|Y!lOX&ZZv;+3bSZcP+F+&N=Y_?XWWm7!^0?oAc_m z=lXo1Q^<~mLByJbB8#m28N*Ym6=CtMP*Gnu&&=qLkqp8*x*r|XW(%BMEc59Scb(N- z9#6I%BPuHSPFKT^mn-sGyxPF^$Y`^Ew8hDsoF-xY_;*C#K*I@Hy>B%BbRV7>cmgpe zvo9pafh!*7ngO+j?!s?AUXxOvVa|s;TH}x(EGp5dJ*R&}DF>)JLWS!{VNi%NDJVC~ zsge{XUIyldwTte!=wxMa)vDUV2*MuoEDvFEkn z`-Ket<<$8d2TptM&l>};Vs2fEgkVuaR6Ik5@qQs0`N6VZZubBsvMkH`?PdI2oujsj z4ZH#aqOW*!31y*}<4hM!4arSkwcYaIDZ2_|T8A4Lb<8B04*r{S@inYr6{Su?cTceyk~UZT&enanshH zp()*Fz#VS&!>bx!DO|-m3O$@?5A7F7eV*4-JoqXh-+js3;SZ6h$0tbIB#QQN%A#D{ z%J^NYQ2hgytX?nD`JpjsylQ0IT%7k6^?Sevg&YYnzBTWvu43Pt!vGEwb7-N4wr%jo;X>TNfo4ovwioc1N-Nv1N}!P^G(jv`z9XA6&{FO8?EN3 TlNKaY?1?cp(qU!hX9fTOta`dg6KWo#x;>DQ z8oLtHji`y<8?J`|QY{FGkEYg49=ev^0Klb~f1F0Or>~6q5Z6QA#ylZx&IWp5#%LI~ zw=@nj@v2Nv(dbZHTB%(|&%e#+ucFW(#~{P9#rQ`;B}QH5U73D_3Ybw>QBAdPu~3O= z{y4mXg;YdKQshD@mgNC8uF%7CvIm-vG>k4LI3_kECJp5SQ+}KbY_#MwEqkQ*WHbc+ zys-=i(vWV0n}o^2dr15>8sOwlBaX9=c7@SbKN*88+Ho`Z?2Kq z92Xm=&}@Fu8c#q`zxUc2%G zW@yHxzi_hle_X_EmkSN6O~KYq(#yjA7wiF{Zwj{utpPnt^83?QXcZ0MTytmgv>_o3 z+J%<}_aup@>07NZcl6MDdDiN7f7YeWWu2}Ph1)BCVV{<*($9Qxh6}-JhOH%gZP&FT z_+sWq-w7l3V0YVqzO8D38WQK{omE<|C3v{VZnHwKer?#y3u=mPR!=zRk`|);uk3U> zN37jM=en_)ZD^@OF6J0~6vmGFGugY({Cm*q!gCB6PN~^D*CBy^xhcWmrS=-*)iODk zfFF9mz5Y*1&H1uk#kk=0BVziC9w~OWx#$jx&ee6X5!(sw;^7AOcA($ktqg*Z)OjUg zt+!KLs(xcP-is&>3Jz&-d@MBiFH&815{WSix&gj7e{c3->AP)dFDpg8WWbb!;q^EXl)+Q$Qz+Zz1aLe305 z42yb-gkVYM*Gvw%iM!2FUc~}a_oD_??{5YC#MOY$T`Au&8HJiPr+4o4b+wqm)X6gj z5*#zT>@EF|0;2d>3)KB7Mp0OFnyIz=a9Br%&HkbySlbkhtG55doX!UqnvEScfk^KsnsbU*K8p_<3EnL$ zh$S2d=>fxQD6PP%c55{uuNV<0spwz#bU04%3gPALXmt(cy7VxTUB{s@jn?Xm+PwWp z-{{~_HUXZ8k zYlf$w4uiA}b;$q#%Siw8{Ox|i3%mo}{voCiib8#FpXDQ(#OluzZaKC%-A&wG@*>R1 zx&ZQq7G7IOYqm>bW}z7ZvdNFwOkK}$Re)*ElT94Z!$ z^yBq&E_M?%TjbcPz6e(|R8l{elKFYY)VRk(V{#|}KmKQR2cO07mT&q3n=4lPJ^Svp zg$%sl>vGJt(H+eNfn+GD{NZz7lhEbWD&)nnjJ#h#9%F;u*n85lL;Nh&=ZpJ`clu2C z7-J$`kU^(=@9xKu7~x1JQ})SbGrWVzyi74wtdT#i3Y|W23iT7;|q;O zEffmp9!FDLI~89}WkW1#83to`T57$jS%oBSI#`6?ala9MJ_nKMEdlj2bFOMaV6G@<3!N8 zEf48L!@yb+Ok3GScT^QOPf!FsG*jlxWv`r0x%s@)9{6}R{Cmu&tE|k(!wqep9xkb7 z`+$Y793VI5G(ILV>d#us-XXSf_6mOKql5Q0rLd=RAKn@;q&7GFz*R6?Z@Hmt+mHJ% z)xh(XCJPn_CUnccQ;r{#DTP;bes{~%gv&I#{y{4+-oBBuUXY%Mnw-L+y~f5~#_2Pb zD%8zV0V_Q2yd)3Fnz3z%1bqPPvdLYX*6r z%;y^=gXu1OUA>tx>?qXlNB(x7bMHqu|JaDnpc5GPR(k1%9yS(d3rXmnV;|(y1)qMc z<4(A*D%c%`wT$@eI*zwG<$9Z0Lnn_Waw=gq*DnYv(4RTjxJuklL9Yf>hE0qoyJkA5 z)QudDT*kJ-9kttZRRr~AO}ntQCKNSyP%6p3Z%T~6^jU<=hl5;2a?*at%wl!v)5*mi z3+8Wyg3gvF$T}H|!pcnzS8bScE_>&s{_W99uWpU|fVXY3)W$4P%x_yWolU}JpeQ0f zxtO#@%=JETu0*xM(;jixftbXqng){(57K|+i0=;WT%OPItPtM>FO}F5cLyy2TjJiI zFGXlg$AuufWEBA21gUJw46<9qG2r%FBBH1xL$1gxZ|8 zOV>0RC-j&hrtj4QUEC zd*pQg^2(D<$JC%ezD92zD*u&jy?;Rz8}Z;AX%e|Y1;}5nmjuU_iMu-NZ7_ekusK$= zU&QMZNj<5$wTDz5gZv$U_%tQ8i5H_4poj&p0IZb1EbwZID#tGG&=xa;5~=3}t`;D; zqrff}oF}Y(orQ`ZW52yk>Yc<5*CJ947bHhzWIoM2RXC;0hL_i>h*bqjR+&l$(n|OU zjT}F&-zqRR@At69Dt1WmpQx&z%HUwW*m z!$(RvXNa`m*y2L{Jp4m}HT}>=fN_^O_umvG-TMPdgVi^kp3huTmi459{&;QMNW`pc z2m^GCW^yxZW6!y%M_|MQwh?^C(H(?$Pnw;*!e0fd$Oez-w*4pJK_V#nY= zL>dM#>3;i(N>X!K<^E}N@Y|QB=4!ufR7gxoNza?Vd%Xn@E7N@8#TGIr(ohUMK5z+Z}lMgi*Ce5(7Rbu_~ri4WD!CBP#+(LQDf^e^>zZFW(> z7bVcql}H3?D3c&?E~qTTkn=rJB~@j4c>q16J1YP7UMD8@9Q&oIEfB81ZC*BY?Q z*~BomA9!YnER)tYSum;dzg3t47!F7t-BQf!u-jh3eTY;M2uKNtfV3bjC?Zul0VLA1 z^amDtl_Fqh(veg%D*>3NhM z4$SB2eMjPJV|rrrLF!|e=`EPqF@`?B=%r`r0|0;t{|cZ=S5G;80MSQjV*)Zas6la< zQQ-OQt#9>vAwOgq!7?V=Fw-`WRIJs|t|?=1E%K6;(p~rRk4hz#Lm%s&)x@I&rarpp z2q+&!T0E$rOO@+D5FXCO_)hmf!yeizR_`?(Wz#A*+r6CqxBBgt`n!*A|8dQE6OpNZ zj9bbM>aR~S4=3sEz8eor3>2$MV=S2Wg~qhF^1{S26fme84@fbOKAUn*#N~=r@#&x) z75`k!(P5Wu{d6fo0~UJm8q0x=%34N|a+Y@Cz`Cy@i5Ce#x20#y@(jKoHJ}n7?n&#Jy#~NtCcLK|88M#dbQeK!|<+@2S;Q zHlNDwj{c?Y3ew2$Knhubu{B(=T7bC&U~G@M(DhVw@Ts+46NSxuyx;o;!C1P?^kO0p z?Y6T>z(mTnaSP)nXTHd{?2z$%6&2AInn!_VnR5qi+iBle}(KM?4CC%S@hH<*- zF}N1@C;KUI^hk?ELQvby8o|H$Ti-6HftR3ab@r28u-;#)=5v1F+dxVC@F8jYFwfyv z=E_+l-Gr!attb59Si7lH&D!!S!z)irSQq#OlHSd@zDla({$iaj>Z8{4MCpBSUi7q^LPTm~Te6Sf#S|;` zZcNef>1nCX8XTv~p3xmS#qf#eYJ&%gVbRb;*)Oxikbs&4VfV|j_YVg^ucbBZ%{IiU zo8n@AKlb?j8La!#nG^|YbThk*aCXHrPXL^{pL-KpOWF!lb<#r&d2 z{nh=eTTkh0E=H0vS?i^O=e8mURC%mLeBoZqulZi(l%m`nqPe)t{UjBz} zg0{232w`leT}mlU8nI)vL1IKyRpX_LEn*mfq9m&ILZ zwWnmeovS84xv)F5PkS57uy6;%4Sf6pBynZd)18>3Ods7>UYEXFy__4B(q;kAUV2KQC z?9;OdEf<)N1?sn;s5lNeae#?*krbHAI^H-zqT4EFG@|a9AQDDi8`+w$sSrHxJs%k} zFI0}NbXm2v-_$N=$x`p_9pSlb%^eC^3^mN}9b9RFDiiAo$<|A5K9%7Kp zG549>YJ5<}#|(q~0(i~oja$c28AQYh#K9e#T2Y8{ddLYos<1jPwr87JDA|t7035{( z6+7n$oR32Z-hwlguQFbKD{K&UMW6H-BY&oR?u&EYY8PbifrkW*8>_x~|#IlK}r_Pl7K>ma87do$e9bZpAK5q1c22^r6FFV7;bRHoV5z z^3PlF$gk-tv#}U@u}o-URRi8+JjZOS$Sx~?Qr-c_^Fze>Ny!N`sWy(NvqNtT^=NkW zrn1W1*AG2IwD(w9rqUN9N;OT#{(>z*3d8DkX_|?0EzL8HikuU<1-ZLMO}t@z*rk+D zW6gwbl~D9}N!FtuO|C(QefH?E^*A9ff)(aVDJ*)6fRK4(%MA5xyr$6$2B-t-KZ|+U2k5mghO_qcEV^d}d2!1)7E8Z@(C|gF5P_Ij9D5+RAPS1PL4I87p$(@S~&K#W@rTB)C(+tX}HH z;y$$?f@t`c9*#|z)$X~2ibP&p#NW{J-=HG3(qw6fI^_6K@*gfsI|o)A4IDx{A}-v; z!_t&lsJwdaG3V864IEi@q9Y$!rkP5!`xT7qQrAu@tRvmFs!I2e=3j_|`z`DRRZ!px zmrK`D4V%#npb74Q>qlT zYSgR|yR=4(2uk?8=e*xP@A>X??)!S4|E}kp=f2J_$;9X$JL_du006+QtAjAT(D93Q zVrIOUU(%i#T?oCermi{jMTIguCtloHymgSi001!Q@1{}i?XS5w2FOOuz$u z)8ZimtC)@*XosdkLU@MtY2?$5j*o%4hs%Srqv`?3seH$^!EKjq+0ZuU&)d&^Ib5++ z3h~w^{cB5&vOA}{Yg66sEnb6Xfge@U%T_gf#Xy@{E?^*lh1 zj4rQ_6s@HQsRqQ&Y}GQRJ-P*?r)3-8DeYR`)xlse%YvjEIEGW7x)bD+!Sw$A_Z8ZgCdKjd**!@NAkUb&?3Zah$arwnR zO=Ro*$8#>j?K%t24B1&@ZD+;*dFO`;$HVi-k|%P<9$gczhs zi1aNWTi6DFzU7zb`vBpDa;9{&p#@L99z{)mqhI4STRcAVnZk5yHOypqcxjP)&Oy^3 zn0g0O8!0cf^%q~LUIJY0WwpJr25(T^qbel=*fLDwD6Mq!@ssJSjHs$wjovx+NZ*N@ zu(}yc*{55c*PPS-$ggXo%`l)mtW(O5M)#RZl!)xX{0bFIjm+H^mb|mefB~G|%ro{`hP1}i} z(9R8!9}niTTm1%O{Z}NKf7s?dsO@rMCd~)l@7B!%j%sFmV6->DFXM(yVJiA|n{YF? zw$0SbbFs%t7MSK46)fX(g0m&XN+Js*h{c=t(){p0mj{}@f*x*devtuxd&bv3*G(N+t`qG&en*MD+|Y28unY&cJV_M(j*JGl7hPT zoLxhVs1n*@0{vof%41^txm?iRM?+Ruj#r9szcZ3YwZuYN(v!)CK_EM}(pWuNva_@? z?i5-UUd+ZVNJ+|Uu-_0S2{G=lN!1bTP*nw%A)Y9HTkt`GfZ7{}9S{5;i)!`tbi`0T0;m;;{^oMKU*m%V9JLc9C zrO>={nhd>m*x~Ig>Jg^|ugKRB5yYB&n0off^s$L?*bM#^G?eHn3IWa9C1lmnrRtiY zB*~h<-<&6VDuoFgaM8^A)IZ1Z&Cj9=A)RCs8u*A%V3AuF6u}_`Cyxe;UT)K9XcZFX zObGtXv*aL@Fg-i=Aw#ra?~Oydz3Th!r?72x zh$6e8v3gQNLIlU;CI%q6PX~b|KkK-OHnM(#3KY6nbu~+`UDF`1k0Lepr3Y~cssLX> zLt35o4i)CU`p^b=+aZFX;S1eKv6MnncCx+#qgKUvb6{&Bw$?ue5u+$=bl%c$*#UF4 z@1At}qIPeYJFSp9)Rw^4=c&#&(j}*uX08cOj?LKf7k<*s#F_HxwvYLwr2Q+Q&+y4s z$y5Isl;91HmnHp%{Bk3=w1mxjC;mdH-HN^w^2^~#}z2VfC$yFG#Sg?hEH zj<}v@^RbAKiLzO<=feyq&BN7KM^LN&6yxOB5i&W`jXLVPMtif6t>_gJNUD+YXQ)i5 ze!W6uy1$<@xrn$4_Q8qdP=-=Bb}vpZGgOh(N&+P#LS|f3YOVHnqg*0Ta^Q zj!G?`D|9sH6Kau@@PI$~C%_}{RT=ZMt@CI;mcz55eA&;x->Kxg+h|m;X2%~G7h4iF zvwv>CwH6IKI7Z>xcoCAaQC**bpRyvJ04++z{SaxVlf%9A_!5jrQL#jM&}L2x^~Q5y zuY$hDr+0WcAk7~J)6X(%WMDQco<)@l%}Y?N-(r0hM9tL~@=Uc=u4Gvr+O6w#T5Fi= zG&&9vRhA9MikHC->@rtK1pTcdV|c?fqcWuAkFESctN<}@ z1_OI3N;*$@wfjkto~NA}sab9ddjx}ui^c9?h;xfr)h?zzd+CF(VUQV8j~P_9*Io?# zqy45Y$0k1WdT67r7^jy?Qcu*Sg}Rw|XB(+%k$Xj_WtaurEoEa;yu{nnT56^!k8BG| zQher)=Ui@+vL0-XdA{@@Q3%Esvc+R{&%*!f(k;8lLU^Z>&hZc&MwM|APlW_DU#T!* zZu)hZXWk!-8~y9Y!4}8`d(MDwi2jyvCH`OAZRj_8 z?$@W~F@IT+TEwXV`x5u=q`r_)H9K#yVQrPLt*4IzJ|kzjXUH|0)Q7CqMHX8*K2~wu z4Z5MWlHyh_;L}#Zmm|oRGqdRkVxOvS&f^;K?)ZQ3CCxvu=Pmq8e<|Z18vC1QkO1d! z`o$-WYVRzr5oVboerxcd482Y#`F7OEs)5D0xila5u>6}cSB)C0caP>?E-ft`FL$R1 zqVd+pI!AxTX+r2}TWq$yMPuO#&keSw@tC!Ec0tOgauZKt%Q4EuWwq3OwA8NGWVQDF zdx7limN#qOeoE#xO&;HyE>JIKn6t9_RT)7NfSWt_@rjWYcQrm<0&oGaNGPzifEFNN z2N@_~AMp;P^c4F?xKs^v@gVMUMJ`nQnbH1lA~WF91YpNVimyA}$pw*S_-_6&lFx*s cFQoXKPDixCqJmsDdx6jZU2P*ottKk^zuFwzC-f)GmRf>MIi#CWJ7^j;!G z%ArURkjja7gZ006KVJk*6=@Wch2 zm@i-CzPFjC7sTKPF@P~&#B1hf@fSUd&qHfJ005Zqzo1j@A1ns|u2>uB-iHO}ZOFwMU>@?ta*JX3jE>=+^6zlX?OVCyDl7vWBQxf1TUjIXHYfUP+bQ zELbs3Y_H@Wc`~x28UAAHEq2ZYOI9V+Gt22Kktf|oY?8o%cg7le=)TjLbQpf%^}!u0 zLQYd^v{@fs($LoWWurqquj)u>fNOJk*$PBh!Ntv@84TiCc&{=31+Zt^rgEz?)#{*K zXMUuvqbn}8`PM_@9}F;IE{6zAQ>gD)(8H>3JXLfo8634ssr`fa^_X;xiDQ`swuc{3 zAT;}yo9hBLYpb-ENzx`&n?;UKcvKA|KD*Zy@a(cAio>rqb#IcDdj#f^#=pW188TtZ z7Bu+{E6Z{tz3#yq<<))mHrCdcA(@3{C>X2@7C4N1&MP^ zN%<@U=m#l?r6pn57+KUP=i?N^FC5julpSN9_NkjWnXMlEA~p+H*cqUBWOTb>nodRK zv(XGVYoj#rTscQxFO;aUsZ%a`MbgX2y8|=Q| z->d*eaU4kCxNbOcfyHhVr6PnNy0^SDTR5CB5-^CaF+@_g`@a;k7FcL_iyQw*)R9WL z%RiZw+KQM2e8v5qvil=DG`h{=J?v`++Pc2j70pFnpd8|UjA73YmG>_?=i1oFU2JRU zvd$#5-P`S5@!GIyY$IK2J9a6FJbBByRHM!-sHZ1DwPfgn%?-T)3i$Buy;2SU-vU3kkD|fXglsSaA z;LAzM2uAlPA%3Z&@m)FJnd0ic)|!-cpt4!$NVE#s(XOHhXbyXzvr@5u3Y|iyYsE1+ z0@5kl64pa|x1&-{M>#9Ih+ByzxggzsFfW+s$+$PO`>(*41B#|nnTG`h$wUoDI=tHY ziA=2hefsY-sM`)E4ckGB=*YO`fq#vYaFN#b9&y|Z?cq|i2=bD{OOv~7SDjM8TwtQF z;+__5kRY$%b7_-WTOt0Zypm_9yn=caEY;eXI8bU_Vqh<8QN9POBB@em)9}@dArc3AHn0nM$5&peMUfxIgV}5H`%K^Sl89*Tw!Mw>}Rj4+^+mZQptm`5Wtg zbMAbRP{HFQg>F8(t`e#0t3uP3jt!bCHlOa-vWmc$51y#r^Sw4s+1aY_@`PYRJC`e= zSTYJ!B#&dgq_^894gR6GFX$L*@J1`dA9i*gpEKK)C7g^U@?n+(#oVDD6n6D<}mTu(^QCRC<)T zIYBm~icpqlyO^OCe9(MXteBz4H@sqZ#p$*ABP`>j)WM^H#waQ5tA0y zMpe7-3m%vE6N(2y^q|4&fw*D2MAd!P=dK*Y0#0I}&`xjpVhbrK^x;BKC4-?f2<=$l zDzmPkC2=+y)|9LHrZ$|r<;c^2+&8{&Or~7LV-lD1c-3AlkfOyU{0h;#;ivycYPmx6 zcVOL;!^u+H!84dy27Vux1BXPVkXalxBVO1?yW7MjT0Z>@@ZJoZ%`=-?Vpw%O*VeB{ zF#lwM3DUFZEIipzraq_fqu^pO?s+CDoS)`dDuYZjdjjX*A)T&8v@P=hM?aD%m7@f| z3(+`e95CZJ&{c~ec*szz###U$g3sOLDBn@?57x1N%gucGEQ1D9e;R44;;nz(!S?qX z*7lCt^f1R&&cv_MDQ3h!0;gm8`vVg-&wnU~(W&3lJ>D2(tgPRqaPwvbZ!TXkBvGge zjrowF@sCYsMq2yaU65QN;G~V+{6Lmsc5#o78v+Bf@?!fkLm0zbFfSo|wVUst%lM4R z7=I)tE@=BG%h@|E{1oTg0E@o|ya8)zW_0;!l?PN_%=2@2-by|`zT)p(CI0!2QsVYz z3|;^h7Af3+6p!39Qpvq7ej&@MgwFkNX0cw&yD%{C=VpK4JOcUVfQnQ(!hlrujyJsJ z=K89LbEGBQo>v|Zz9sg_%!_XW6O5bwjW7Db&fQL3gk=|)IGu75QHB!}KkY*`E+lSl z^qwBh9bF)Ds@YkI>1+!qSiIEDa-Poq)BfP4Q>(Y0;%Zx!Wg@=)B(zJ}v8V0KYER8q zj}ejaNVo6?ZodI3!5yD7WT&O>6Lp9YS=u~QuAinkX{p1`Ssr9 z9bfsH6I51NP0YZ|EAeIHH}%fqsT1CPdMtjKQKTTm-bYY-O^hKQsr;ekq#iZS*p}6a ziD{X!swDnmEqZy8*&uh&6 zNSceMnj&_URn7$=1Z7vl{QYFdzMgw`ARi=a6;f!pWFIDkcT;7cTh|ZIu|`Vj#$*KK zKu_9tqjjT5GL8QfeF-!($}K&~m37uUcopS%@4gRQYxU^!gV5_MA#1h6opY~M=j*ZB zGG4uhf$1l!a}2WQcsmjO_^1JO%80-z@$JV+LJu{41TfY3x}^|JN>=`9*A)5d-@mgk zx3@Z2wn!ip9oQkp#`ki|k@Vp-&}Y&+YFf>B()=rXIQCazN=>++80#%6%H}$Q#O|5e zI#wg1@!<08V9NS*im*p zF8s|as!3jw@={)?W(y)<9{6M3(}}~c4d{2s{FFS1Vp6{oMnrhla}-;RJxElNi*KjM zU2KkE&45@=KDYYaTV`g62>GylEzs30M7$a#9lvszPUuO&bf*jmYE}o!B+g}^o*4fJ zUqQbgumjQ6H+b~_t;gNwO#Q8J+)H@Y{1w-p>eO#b0{V`1-F`1u+w}+C$j{&p8J0>PT?Im2aa!BCb=7f`-+Nuu z6d5gWhEQo3Jj|Iw5Ev;rX<@inF#DP+s+AFW8K{)-m4lq(pkutJCz< ziyiQfcBhQ9hh1NjO`#63*Mb2tzBkk`&N<4!859_?#05*}y+9uTpC>1tq`DiYte`oh4egEPW={KtL zdKnR*&0WP+LN6!*|8eNt-$pV?TSuQnPD){LzNU2pHbD1Y93+FmP3+yRtg)=gc0?$? eoylW@Mt@~Y3iou>m;d7P02n+l)vbWQqy7hoXjFax literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_pressed_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_pressed_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..972962dcfd074526eb79aebfe5e849266d256693 GIT binary patch literal 3384 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/ic_plusone_small_off_client.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/ic_plusone_small_off_client.png new file mode 100644 index 0000000000000000000000000000000000000000..6174fcd9b1eb095b2b37d915ee1c90387f1f3026 GIT binary patch literal 1205 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 ZLN7j_zEMK+un{~`fUTt?SV!`|^dFvJZ!-V@ literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e94a49b0ae8f052d08df086f018b3c2477803246 GIT binary patch literal 2457 zcmZve2~d++5`cdoKtR+41yKY^jDU!sAR{0Hh<}K2CLCja!03n=ZiX`;N4P{YgaD$5 zN93Fc0|o*r$1un(CJ5mcTqBpD3C9HFkZ|f|s&=<(YqzWVef3_~tJkl)tGZL19B|u} z_bCGaupNIE{7K5Ie=A%;x|S9x?2rORvBMMLQi+9o(xrQ)kh2#k0I)6PZC6=EL>e}u8A?1b*&?!M#2+n#)JmU5j)3 zcbpgOEx2x*h=K81QW|UusXZ23XGnEJ<$*_QTwTF@W|!xopT*UU{SBfA7$Rf~x*<7n z?$L@i$GXF+~ZriGb8y#E4t%@2{9<2vWHZPtn`anT+<^%wRcNQm`ZFzL%T_Bq{=DGd&;B9n!uf+av5g zMmJ72G|2;UfPPtZUha;*Qid z7d1Zy1Hd-kkifD3MBGnf_vxO;G-5mW?rFTqG4@PIjRW*YF2yzN_@w!*{PHgu=6a;+ zM-0|KyoDE?2+iQ~YL%Q{S}0hxZSdF$MGH|mb$)W&%p9%%5dy6${e%njNm_mQ%;8{@ znqt2gp2kvioP}xAebHJ*&!43MznP(OC=UP~=0yzmAq#(zoMy_6ec`E=(*B7uJ^siK z3l|MHTS&qJpW)iLW~cC(f5|o{`LWp#u!WRc{ztUDg{QryW9J)n&^i;ouMJf1=#;fU zzF0W&9dWQrFhOUE4K`3Ly{Gj_a~tN@IsFU-+yBbzma9T}A29}TToL%gb1>yoI!bDw zw?8dh?4l+>kf!TBovW8qj_*8~yL^Vl!E;KiafmyF`MAkaS){yr&(~>#yYc!}CQn|4 z*6X3)qr*H~)$io8^mD3LUg~aKFlmb>^Ka+|rn3IQU)mJEiv(k9o;_Qb*9|mIa=Ceo z`w^@%Mn~)#qPN$uuimXBK?k9&xnSG2I5Pi<1kJC`l~|CrtJav|eD8a?qb4fXEujW0 z=8u;HRM}UAv%qc0z4*fYxTl5=gYqOwEW)|e!xQEAl7BLlRU7&f70I-DOp(5?&#=5h zb+a$M)pO-o?Q9P91oOvH+PD071?=q6jr;@J+CiXmRW{}|86-mT-nW*lnvSB4?U>mb zUKds*MxGxWSP?tlkWPhlkC26$kbRH>qy4C8Sj~GB1l`kTne<^8kV+?`*PqX#0hkWV zHrlIXX2hze;`q|9?4VMA6+pd1X;Td%{PtZIH*_;T6QlQQ*X&T=e%$_ZP(ye~$mbX9 z_Os7_PeRBRq-hoT)s?a{aw$}_YAIVD@DlEUB8rD@a;g=J#gQoy;rn@kf2ao-XrR1x zSlrOqwnvuc=23gq&!7cZp4hxj)#&oIRt?cGS3nIr4U5DY$|3cZnDy@_ro-2N5Djm& zT=_gUsh#Y@iTjnF@Wj|hNDvLz`)r-SXMQtW6UUrev72HbdVp~Q;7x9Q8Z%g0w}kyX z#|PUXu&r}(JUZ_!?ncpjPO5_nK^plW&eqh!LBBjvlZBPl<`?!_+HLqE!wGVNUh<#N z-Jo<4`P>gW&`8J9ru}|i21|eDl7`=JTw2yrMP+C$Egd*O{p}b`22bIoz`cv6DgMJVkuE?}GuTOIVbiCuM zJED#Gy=+TE#sn!7lTk;!_Ktyo2m@t9X0*k`7&2cEtjhm=dJb=$L?1S0Oq_Gx-IVyM zR4$hi%xD*em~XDu#=YS@iMW8{^)V39d1F!!U=-9ZXaQkhxl;FxGBPw1L*;MM=zo>? zkL1(A!k{^$zYZ2I@~f4d2kS=5{D1aYHSGNA&C#lOZVcZ15E6w0tu@o_=lS37Q33#B zL@G1TRmiA*RDpHAO?F|v(fxB;3$b2jL%fU7Meyp4Nz;fknDm+^5Sr9aRK6y z%DIz-fr`7BwLNdN?;D|W7mf_+-lRJ8g$S$+yeKa@k;?(vU%A6p2i+jnVQiH5b zl=scO5@?5TZaAR|G&9;)GCv(T4<+{Gyg(w&*ul!QY9$Yj*1?I^7U#i$$9+@9-G9a~ z@dL{@3_G>+ikfDn43aYuIT`=@t`;2O>ZCX6liJ?~{|0-y#++28bVUANGZQ_yxjxJ1kl?LHB$w z%L99O3pNwx@%^tZt&nK8;L{=L<&lbxLm4VKwk2`!I>jiWJDomt7;T9*=os`T4$|9; z*p1T)Szidr;4(p)xu18-6wnIX)ef#Zfpb6V-hB&2lq&aj*$MQ~t}^57_Gk7Pc7A!* zWvpt+3xnpgp+zM4ao|M5Y(vw>ocA(`9uc@HLsV5-eTQRgDt!`z*WO27EKdb`!>*Rp z5h9K8ne%0bktlBmc8aEqZA!aqem5q@;I zS#SBu_)j~9@(ee%DkWuKat?Hr!xxmdviG{;s;#bV_f=g!Un}X;C~q=>Wdp#<{IunE z&eu?j=Eug|-e!|P-L{Pc>%{!6j^?hn1B)IpKH}+}`)P|c#fte3A0A6~6kJCTc24VN z`E{x6YlMBVz?JsE04@+Rk-nzfTiX#N`$=ncM-1{2%gLoId@jCGq%I!gYwT!1T<_h6 wg#QaAY@m3zui59Ke90;=g@7&?n=@>0X%=4g8%>k literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e94a49b0ae8f052d08df086f018b3c2477803246 GIT binary patch literal 2457 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_disabled_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_disabled_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..9044a118af72c90631cdf1edac8275078e19d3d9 GIT binary patch literal 2438 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 ZLN7j_zEMK+un{~`fUTt?SV!`|^dFvJZ!-V@ literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..bfe4f04639ca1e4412ef1cacd6e8099c55a41dad GIT binary patch literal 2886 zcmY+Gc{~&TAIFE8VP>=#CWdcTk%=Nlm@#LL90|E|<*3FsbL`776*`c+P;%u+k=(Zk zQ?ca86{3(c7JmC3e|&$R$K(BZKR$oG->=X6@qRvD36>Y}0(|0p002P1*a&CM&hGyX zFo=DZJ_AA733v-@Yy)PWaIhzx{pJlea<~Nm@F)B`IMm+ty#N6C7L9RwHl*yIIgZzn z!(!cs-Yb-izphfM)zxnZ%U78rrE9Um*2pC+6(Ib`!h!)) zc`r<4ft*-Vz7$<77w-#xbE-lIYKOm84w|%DzdVtXlW}XWa$95Bp@LbPGm6o9XFabe z`Zy=*+5oX>LsH4@?%%NJ8*PS8$@MXJ?ix=Bb{U={Rsunofh9flr@^#J-Xz$$R-v}z z>e$afJUD9#>~>`R3Tgb${Qc$dm!x|18q=CDH)BKzDvH%@xq(rgAgSg1Io3{GJ{-6l zKnvGcF+$XCNqE}gwepS&bQM(#zvsn+<#O*)O)sZ1AY3ge;MS-Q=PR9Hot{{tT#qQ{ zR392oFn8pj^0>~GJWht;)F6}64YFj{J>$$p3>K;qOM2F(#-#% z(@bVjEdqQr6;`Sg`+)&$dWFPFgJn)lIR#Q@H>86E$P^&E$~#!-1btNfUaCweBu!M| zz=b8QC4MjKE1Y;`Zj*OBHbb-KdDCp%Hn+^e?#6ZrqkNu9seTB0Y5IBt^_z>l(@qdD z8_b?c%sq{f^=_(Atn&1d)PzNkGk`9A{bHemCD#~62TJ}7zRT$aIg*eHlC$%r8>a&=%SEf6l+Y)fid9-%#F zt?aTuWSrC$mT&m};^32z?CQ0LX2<+@WD)x7@9n`s6tUdl{(H+yDz_t+NA#~Uz&An_ z7j@xmWqD@+t6xNdk11^?h2kb7tI;*s?zX)|R2O3>S(I_uEAl3-oTlo1Iwh{Jm1WYh zYtnM!j7fR((ePL)T#u7ScGL{h2&t1@&ALB11k3JAbqETSEK$?;D6vNe^@gE9Zg*vB zf&^z+I@s_iv?34@OWE}!ji`E$SRB9qXJ#%vOINnB;Md5h6g4jiRGjNu=+@j2#PJ<5 zNLgOUvH&d_SYQPwn|FLu9`oe3HV@dNdR2MU%gadY?cTa4dd^dvS8vMRLV9mCXE9=B zu;Ac)&78M<@b+^Z%;-0Ah=bioa@JB6r&kO-7PeG88?5L6Dwk6+J8c7+@^9j(61R4ZfdcfmwBBDuE~QHXtQ#vqaEYm70`ljD6>8!qTxsZrW3$A%&ELn{5JuVTq7 zQ&ZYh;{~*UdC{9y6dSGpl&c?Sgpv-=)?%K`^%LEp-UKGJ=Z?75)>Kf7w=uf3VFyL? zpU1G`C?2lgZxY>d>7~HTZSRH{0i$k?~XB#47j=K=u+{K z3~m~=8S{`a54WMOuO7l~MzHxvUPA1-P<%g(jtw2IU>6F%X8w>BrG^%|VqwM?JL694 zu4?Fb)%$&^Q+dKQk9_W)=ZZ!1FX#N5vnRe@S0#RXvY{995|k00zrt=bf^!qR;iRxTO;HFd^)E>KS+m5yDvdn zI;1F8se&3b5%wmtoc7@rTvfc4DItZOadoun7tn{>fVP4iT8Zre1>5>O`3O>wns7H1^_GGk z;=|CqSV9Ep%rM*GNH7~mbd^#RQ<2lksUXbCFiPrf)3G8vR9BM-8X9pnpd53TOACaE zO**K{B>;WJPA8I*=aP<-v( zcySkwq}kJH53@glJOIz&RcrC|?Ew5S>>LHp4G;#9D-#QFfpJ&yC#iDO?6G)=>ug;f zGHwBmr;kIlIS6asWxWIWU!a(UEU}+4|8JmRX}3||2#yCul`28 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_focus_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_focus_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..876884fad79ef8a0639fadc0239705895262a11a GIT binary patch literal 2908 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_normal_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_normal_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..b3e6dd5b40d30c6ffffea2f3b703cdbba33b644d GIT binary patch literal 2847 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 literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d182b5e2c34820b0f2c383ec5fd5e16e6750498e GIT binary patch literal 2569 zcmZ8j2{hE(A0ItMiVR|SmP|zRNMme0+iU!YFmGfgk$o&7OUXW#UScrFWJ`p~_R~<9 z5o3F$$uj8K=E+v}B}Q3lklr}w|IYcJ_dVx(zvq6>_kQpF-t+n1&rQN&E(iS7y>zxw6A=+o!wNPuhIfI zj|J1T1a96f7=KvuN2r{ruy#T)?@33 zGQv|pn)*nZx*dI(q2xW6?@YSLW@NT!EzTnLen4J}Hdv;|eUIuGL7|?4{6QCgU7ycN zG~nB?O3F+O;BV^_Mjw2KiWe&K7Cio2pC}^kks=OaXi^S|^lEHc=+q!i|#G`4;!cM zAI|dRBB9CvPT}kOGl!AzSAfL!HQ6?MC4t;u4K$Gjj)FcUtg2u&y`nF+49oXh`oHI1 z-uQ43Qs8EE{I|(}UHhdZVEHzV79UuU{{LDVS!E85Fv483u?Bn@bP%-x!8FNA2y}id zG}}|33CsNZb^kM5IWB9tu?2<>x5aCeFUb^C>8ev{qrDAI{6g9O%4lUc9R&RpZGc5%Uida0rGbESrb8pewKO>Sfy-H<4vVzj|9Z&+!4W%NKsp#Mgp6@7WSVn z3T3m|KQw<Ol^pE5^oAqk<*L8V5FOY{EwEZ=eQk3+aCLYdn>jAB>N+|+yGU|sz zES3Mtm}~Ku2^Yo3x0dc*@k@8wUKB+M_^qV-moz-vB1;`S zzA;pj9}Z4jZ7xgh%sHEX-iU}~(nbh9IgA2n!XRw@*{nng$uMLZ;`|O<>>IUe;Z8ns zFy(o0IFTnfpQ-8`Cr5Q4FIf#WkL;)8rLQecGlEuW|ik#I=U z(L3==V|qL5cN>m?iOf^0(-xGsiu@%HZk~ijyp4+0x1eA~d+W$w?y7aS ztbUoOQLEOWB>;d2b^LVlRN@)VLA~A+hFLVaCey%2f3`Wcdf7{`_GAJxSEaY1W;zOm zH`LwquEI)v&`N0hK0u? z2|s-)Ler;a<1H?NnVZz%#^;}<)TxfEc#VMFTDo8(F=>a_2A8)9aD+&D<&v3wc5CJG zHYTq$EI;@p;b;Zo4UEl0o*02xC=!}R%=H|xo*(mg?!xcd^%cKYF_)lIUw?DygCej=If8f;zlA0Us3_I^u`C!AO+#Kq9kFLm;<5*1^aDPrcj++7;o_lOz!bHkJq!78hC zabSear?zA@wl^CQvqO60Y>w~4<2SkC276b4-u76rwRJj00gYG2hrlUsU?_M^Z8xRo z18kZR;>4MchzYY_;lEZZ#%l_Ri5*M$%_=U&H(`psbBZR z=f`a49YCsnvvOTOqyiAY5hr%$^NV|=4`+(`?I;uPx5uf8L8QlJ@iD~1q_ff|#| zF&(|0>*H57BF7E-IAuQD$MOzmgK*sQTb4(%NP76_s>^+_0UyJpGZdu=0C+ic=TCKY zoTq(2|1QcgkRhiTobR;$$|0pQWq-vGwDS0-AyzYb$L`}1SJwS&pY27UD)C^WH?zQCng@bFiS7SzqkR*IyGWRmlPC(C@2v(jCIEH%pgeYf^_MB&8V)P_csNz?R?!gNzSoyng& zs$XQ1E_$_a@}usRE)uR6{#5DyoQvyipggEwYK)O2G@aEx_xYvH5HlBv;-J=f7z$uJ z89}l=-&rKHKCK%}Dn2fFO@L43QBGX|JjhUjmB*Y+Gc^C;FUW!z8I*vRnXp2>y|=rz za$GI{f4Os?T#;_+Dse{A8~^(*>~k#HC#G}eT+gtMk*6-Lz6 z-kmH<_>>8rIiJA@RI{-XwvY|WBuss; zJVaLbzh#m^v4ZE19{qWC8_|aKH+EjAB~IOI0J#bw$+mjGN6I(z{&EltQw&grcKzcY DCt%hT literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..47e2aeaf32a15aa78b4fd4edaa6774802d4b33cd GIT binary patch literal 2571 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 D?`GxW literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..47e2aeaf32a15aa78b4fd4edaa6774802d4b33cd GIT binary patch literal 2571 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 D?`GxW literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d182b5e2c34820b0f2c383ec5fd5e16e6750498e GIT binary patch literal 2569 zcmZ8j2{hE(A0ItMiVR|SmP|zRNMme0+iU!YFmGfgk$o&7OUXW#UScrFWJ`p~_R~<9 z5o3F$$uj8K=E+v}B}Q3lklr}w|IYcJ_dVx(zvq6>_kQpF-t+n1&rQN&E(iS7y>zxw6A=+o!wNPuhIfI zj|J1T1a96f7=KvuN2r{ruy#T)?@33 zGQv|pn)*nZx*dI(q2xW6?@YSLW@NT!EzTnLen4J}Hdv;|eUIuGL7|?4{6QCgU7ycN zG~nB?O3F+O;BV^_Mjw2KiWe&K7Cio2pC}^kks=OaXi^S|^lEHc=+q!i|#G`4;!cM zAI|dRBB9CvPT}kOGl!AzSAfL!HQ6?MC4t;u4K$Gjj)FcUtg2u&y`nF+49oXh`oHI1 z-uQ43Qs8EE{I|(}UHhdZVEHzV79UuU{{LDVS!E85Fv483u?Bn@bP%-x!8FNA2y}id zG}}|33CsNZb^kM5IWB9tu?2<>x5aCeFUb^C>8ev{qrDAI{6g9O%4lUc9R&RpZGc5%Uida0rGbESrb8pewKO>Sfy-H<4vVzj|9Z&+!4W%NKsp#Mgp6@7WSVn z3T3m|KQw<Ol^pE5^oAqk<*L8V5FOY{EwEZ=eQk3+aCLYdn>jAB>N+|+yGU|sz zES3Mtm}~Ku2^Yo3x0dc*@k@8wUKB+M_^qV-moz-vB1;`S zzA;pj9}Z4jZ7xgh%sHEX-iU}~(nbh9IgA2n!XRw@*{nng$uMLZ;`|O<>>IUe;Z8ns zFy(o0IFTnfpQ-8`Cr5Q4FIf#WkL;)8rLQecGlEuW|ik#I=U z(L3==V|qL5cN>m?iOf^0(-xGsiu@%HZk~ijyp4+0x1eA~d+W$w?y7aS ztbUoOQLEOWB>;d2b^LVlRN@)VLA~A+hFLVaCey%2f3`Wcdf7{`_GAJxSEaY1W;zOm zH`LwquEI)v&`N0hK0u? z2|s-)Ler;a<1H?NnVZz%#^;}<)TxfEc#VMFTDo8(F=>a_2A8)9aD+&D<&v3wc5CJG zHYTq$EI;@p;b;Zo4UEl0o*02xC=!}R%=H|xo*(mg?!xcd^%cKYF_)lIUw?DygCej=If8f;zlA0Us3_I^u`C!AO+#Kq9kFLm;<5*1^aDPrcj++7;o_lOz!bHkJq!78hC zabSear?zA@wl^CQvqO60Y>w~4<2SkC276b4-u76rwRJj00gYG2hrlUsU?_M^Z8xRo z18kZR;>4MchzYY_;lEZZ#%l_Ri5*M$%_=U&H(`psbBZR z=f`a49YCsnvvOTOqyiAY5hr%$^NV|=4`+(`?I;uPx5uf8L8QlJ@iD~1q_ff|#| zF&(|0>*H57BF7E-IAuQD$MOzmgK*sQTb4(%NP76_s>^+_0UyJpGZdu=0C+ic=TCKY zoTq(2|1QcgkRhiTobR;$$|0pQWq-vGwDS0-AyzYb$L`}1SJwS&pY27UD)C^WH?zQCng@bFiS7SzqkR*IyGWRmlPC(C@2v(jCIEH%pgeYf^_MB&8V)P_csNz?R?!gNzSoyng& zs$XQ1E_$_a@}usRE)uR6{#5DyoQvyipggEwYK)O2G@aEx_xYvH5HlBv;-J=f7z$uJ z89}l=-&rKHKCK%}Dn2fFO@L43QBGX|JjhUjmB*Y+Gc^C;FUW!z8I*vRnXp2>y|=rz za$GI{f4Os?T#;_+Dse{A8~^(*>~k#HC#G}eT+gtMk*6-Lz6 z-kmH<_>>8rIiJA@RI{-XwvY|WBuss; zJVaLbzh#m^v4ZE19{qWC8_|aKH+EjAB~IOI0J#bw$+mjGN6I(z{&EltQw&grcKzcY DCt%hT literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_focus_dark.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_focus_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..64e97068740db4eb29c82df7a6292dcaf419e397 GIT binary patch literal 2939 zcmZXWXHXMb7RO@%4FMj6-dg}M(pIHvC?OD#79gO4pbrq~q4y9#z<|=86j4Ar1c-pr z0*Hu8mEMaqX+ba)>2337cfY*7Gv}Ur@0|aK|I9sSez9m{6bqOi3;+OF^!1Qtv^+u! zJJ3bi-kz9dOiT1W2z?BQwn9M;1lpa^Q}3P+0KgRccU(~J>?Y9;Li$K8Okn25cf2R( z$c0Or)TycCQz)Z8C?XulT@VT8LK2-WqyqD*5yjQ3Dr%!$Yl)O|=rGa8KvAx!zC`I98VQyle(6tK+wYsBI`iifrs3-oc$T!b=yJHA=TS5$R8 zyG8F~-FQ!qEie3>=-xt%csB@;i78DFoL=KQYd#V&I1Q9qH@o~F9|kFYId7!^7>|7plG$KyU$E zc2rXIaLvxNUEa`b7^Zb8W`DbL(}c|b%PYNAwfc`%%9cWng?~fi(Pa~I$k*rxrfOx~QUjZwQ5tg&WNnJ4vibl=Ite-hM_sdC zi`ifM`4g5ymxTka#K?#6Wj|}@DWxE7U@j$198#_LUB8Kano2C*V{BNnC|7ukBw)1E zx)E_+O7T}tE@_YBhSdavN~s|rw6U^SZ5XK#XZ;|UJJ|I-@z#y=5YI$@duxH%;C!cC zaPLc&!tz_kwvL1SQ&zGYWhkiA>~9fsvZorPelK`xQg2v5hcVT4)e|E_zFBODb&mPw zATu`5v|eW;Na9A+f5&-1O|e{(7#H^}qT$w_8>2k&XNMr%4aQ^4!?;o1<38q@WOHo+&PHQ>EguI-EE4ND= zV5xP}%9JkQkr&igU4&{a))iI(Q!!3SjBd3omh8HyLsPgcC&Uj&^oi~MqWVFyOmz5) zIM00ra(;$G1HO>)lg#xG@O(tNW0?`?GLK57>8A>IB&!hOaG35OWfF+Jd?44=7@5`@dS2XC^Hbndl!RD49hU}|_N;-(ifNgm#< zX{vwaOhV@hgIqNoezgT_WihhP%}hTYM{P+(mNViIMCB?*_eSLJ zI}bA7&-B`=U!79z1@i+WYOz&kk_0p&cg;cKg&wYohj@M4OzCli^G%|2Q>TF>@j?0V z<)$$6jQsMGOn4OXE7}`X8d}|UvA#VFUWYbC@2qmD9JXIh9K7l!SXK@OpHEC z15neHk1`I#_4BVa&dgAdn^VeA+<^gdw8^$5jXfh3S(2$(vuWJGp6$gk#~%dA)PDL# zIKqQh!OoPolb-gs(6?-*gA()*et9mGC!0pE;);qzo(ePa99XmYNxPIpbu&V4%H;o^(eg(1J0@?|TA`*3b$sdyq zMc)NW3g%u*k#B%M)-ndLsfz%|Y!lOX&ZZv;+3bSZcP+F+&N=Y_?XWWm7!^0?oAc_m z=lXo1Q^<~mLByJbB8#m28N*Ym6=CtMP*Gnu&&=qLkqp8*x*r|XW(%BMEc59Scb(N- z9#6I%BPuHSPFKT^mn-sGyxPF^$Y`^Ew8hDsoF-xY_;*C#K*I@Hy>B%BbRV7>cmgpe zvo9pafh!*7ngO+j?!s?AUXxOvVa|s;TH}x(EGp5dJ*R&}DF>)JLWS!{VNi%NDJVC~ zsge{XUIyldwTte!=wxMa)vDUV2*MuoEDvFEkn z`-Ket<<$8d2TptM&l>};Vs2fEgkVuaR6Ik5@qQs0`N6VZZubBsvMkH`?PdI2oujsj z4ZH#aqOW*!31y*}<4hM!4arSkwcYaIDZ2_|T8A4Lb<8B04*r{S@inYr6{Su?cTceyk~UZT&enanshH zp()*Fz#VS&!>bx!DO|-m3O$@?5A7F7eV*4-JoqXh-+js3;SZ6h$0tbIB#QQN%A#D{ z%J^NYQ2hgytX?nD`JpjsylQ0IT%7k6^?Sevg&YYnzBTWvu43Pt!vGEwb7-N4wr%jo;X>TNfo4ovwioc1N-Nv1N}!P^G(jv`z9XA6&{FO8?EN3 TlNKaY?1?cp(qU!hX9fTOta`dg6KWo#x;>DQ z8oLtHji`y<8?J`|QY{FGkEYg49=ev^0Klb~f1F0Or>~6q5Z6QA#ylZx&IWp5#%LI~ zw=@nj@v2Nv(dbZHTB%(|&%e#+ucFW(#~{P9#rQ`;B}QH5U73D_3Ybw>QBAdPu~3O= z{y4mXg;YdKQshD@mgNC8uF%7CvIm-vG>k4LI3_kECJp5SQ+}KbY_#MwEqkQ*WHbc+ zys-=i(vWV0n}o^2dr15>8sOwlBaX9=c7@SbKN*88+Ho`Z?2Kq z92Xm=&}@Fu8c#q`zxUc2%G zW@yHxzi_hle_X_EmkSN6O~KYq(#yjA7wiF{Zwj{utpPnt^83?QXcZ0MTytmgv>_o3 z+J%<}_aup@>07NZcl6MDdDiN7f7YeWWu2}Ph1)BCVV{<*($9Qxh6}-JhOH%gZP&FT z_+sWq-w7l3V0YVqzO8D38WQK{omE<|C3v{VZnHwKer?#y3u=mPR!=zRk`|);uk3U> zN37jM=en_)ZD^@OF6J0~6vmGFGugY({Cm*q!gCB6PN~^D*CBy^xhcWmrS=-*)iODk zfFF9mz5Y*1&H1uk#kk=0BVziC9w~OWx#$jx&ee6X5!(sw;^7AOcA($ktqg*Z)OjUg zt+!KLs(xcP-is&>3Jz&-d@MBiFH&815{WSix&gj7e{c3->AP)dFDpg8WWbb!;q^EXl)+Q$Qz+Zz1aLe305 z42yb-gkVYM*Gvw%iM!2FUc~}a_oD_??{5YC#MOY$T`Au&8HJiPr+4o4b+wqm)X6gj z5*#zT>@EF|0;2d>3)KB7Mp0OFnyIz=a9Br%&HkbySlbkhtG55doX!UqnvEScfk^KsnsbU*K8p_<3EnL$ zh$S2d=>fxQD6PP%c55{uuNV<0spwz#bU04%3gPALXmt(cy7VxTUB{s@jn?Xm+PwWp z-{{~_HUXZ8k zYlf$w4uiA}b;$q#%Siw8{Ox|i3%mo}{voCiib8#FpXDQ(#OluzZaKC%-A&wG@*>R1 zx&ZQq7G7IOYqm>bW}z7ZvdNFwOkK}$Re)*ElT94Z!$ z^yBq&E_M?%TjbcPz6e(|R8l{elKFYY)VRk(V{#|}KmKQR2cO07mT&q3n=4lPJ^Svp zg$%sl>vGJt(H+eNfn+GD{NZz7lhEbWD&)nnjJ#h#9%F;u*n85lL;Nh&=ZpJ`clu2C z7-J$`kU^(=@9xKu7~x1JQ})SbGrWVzyi74wtdT#i3Y|W23iT7;|q;O zEffmp9!FDLI~89}WkW1#83to`T57$jS%oBSI#`6?ala9MJ_nKMEdlj2bFOMaV6G@<3!N8 zEf48L!@yb+Ok3GScT^QOPf!FsG*jlxWv`r0x%s@)9{6}R{Cmu&tE|k(!wqep9xkb7 z`+$Y793VI5G(ILV>d#us-XXSf_6mOKql5Q0rLd=RAKn@;q&7GFz*R6?Z@Hmt+mHJ% z)xh(XCJPn_CUnccQ;r{#DTP;bes{~%gv&I#{y{4+-oBBuUXY%Mnw-L+y~f5~#_2Pb zD%8zV0V_Q2yd)3Fnz3z%1bqPPvdLYX*6r z%;y^=gXu1OUA>tx>?qXlNB(x7bMHqu|JaDnpc5GPR(k1%9yS(d3rXmnV;|(y1)qMc z<4(A*D%c%`wT$@eI*zwG<$9Z0Lnn_Waw=gq*DnYv(4RTjxJuklL9Yf>hE0qoyJkA5 z)QudDT*kJ-9kttZRRr~AO}ntQCKNSyP%6p3Z%T~6^jU<=hl5;2a?*at%wl!v)5*mi z3+8Wyg3gvF$T}H|!pcnzS8bScE_>&s{_W99uWpU|fVXY3)W$4P%x_yWolU}JpeQ0f zxtO#@%=JETu0*xM(;jixftbXqng){(57K|+i0=;WT%OPItPtM>FO}F5cLyy2TjJiI zFGXlg$AuufWEBA21gUJw46<9qG2r%FBBH1xL$1gxZ|8 zOV>0RC-j&hrtj4QUEC zd*pQg^2(D<$JC%ezD92zD*u&jy?;Rz8}Z;AX%e|Y1;}5nmjuU_iMu-NZ7_ekusK$= zU&QMZNj<5$wTDz5gZv$U_%tQ8i5H_4poj&p0IZb1EbwZID#tGG&=xa;5~=3}t`;D; zqrff}oF}Y(orQ`ZW52yk>Yc<5*CJ947bHhzWIoM2RXC;0hL_i>h*bqjR+&l$(n|OU zjT}F&-zqRR@At69Dt1WmpQx&z%HUwW*m z!$(RvXNa`m*y2L{Jp4m}HT}>=fN_^O_umvG-TMPdgVi^kp3huTmi459{&;QMNW`pc z2m^GCW^yxZW6!y%M_|MQwh?^C(H(?$Pnw;*!e0fd$Oez-w*4pJK_V#nY= zL>dM#>3;i(N>X!K<^E}N@Y|QB=4!ufR7gxoNza?Vd%Xn@E7N@8#TGIr(ohUMK5z+Z}lMgi*Ce5(7Rbu_~ri4WD!CBP#+(LQDf^e^>zZFW(> z7bVcql}H3?D3c&?E~qTTkn=rJB~@j4c>q16J1YP7UMD8@9Q&oIEfB81ZC*BY?Q z*~BomA9!YnER)tYSum;dzg3t47!F7t-BQf!u-jh3eTY;M2uKNtfV3bjC?Zul0VLA1 z^amDtl_Fqh(veg%D*>3NhM z4$SB2eMjPJV|rrrLF!|e=`EPqF@`?B=%r`r0|0;t{|cZ=S5G;80MSQjV*)Zas6la< zQQ-OQt#9>vAwOgq!7?V=Fw-`WRIJs|t|?=1E%K6;(p~rRk4hz#Lm%s&)x@I&rarpp z2q+&!T0E$rOO@+D5FXCO_)hmf!yeizR_`?(Wz#A*+r6CqxBBgt`n!*A|8dQE6OpNZ zj9bbM>aR~S4=3sEz8eor3>2$MV=S2Wg~qhF^1{S26fme84@fbOKAUn*#N~=r@#&x) z75`k!(P5Wu{d6fo0~UJm8q0x=%34N|a+Y@Cz`Cy@i5Ce#x20#y@(jKoHJ}n7?n&#Jy#~NtCcLK|88M#dbQeK!|<+@2S;Q zHlNDwj{c?Y3ew2$Knhubu{B(=T7bC&U~G@M(DhVw@Ts+46NSxuyx;o;!C1P?^kO0p z?Y6T>z(mTnaSP)nXTHd{?2z$%6&2AInn!_VnR5qi+iBle}(KM?4CC%S@hH<*- zF}N1@C;KUI^hk?ELQvby8o|H$Ti-6HftR3ab@r28u-;#)=5v1F+dxVC@F8jYFwfyv z=E_+l-Gr!attb59Si7lH&D!!S!z)irSQq#OlHSd@zDla({$iaj>Z8{4MCpBSUi7q^LPTm~Te6Sf#S|;` zZcNef>1nCX8XTv~p3xmS#qf#eYJ&%gVbRb;*)Oxikbs&4VfV|j_YVg^ucbBZ%{IiU zo8n@AKlb?j8La!#nG^|YbThk*aCXHrPXL^{pL-KpOWF!lb<#r&d2 z{nh=eTTkh0E=H0vS?i^O=e8mURC%mLeBoZqulZi(l%m`nqPe)t{UjBz} zg0{232w`leT}mlU8nI)vL1IKyRpX_LEn*mfq9m&ILZ zwWnmeovS84xv)F5PkS57uy6;%4Sf6pBynZd)18>3Ods7>UYEXFy__4B(q;kAUV2KQC z?9;OdEf<)N1?sn;s5lNeae#?*krbHAI^H-zqT4EFG@|a9AQDDi8`+w$sSrHxJs%k} zFI0}NbXm2v-_$N=$x`p_9pSlb%^eC^3^mN}9b9RFDiiAo$<|A5K9%7Kp zG549>YJ5<}#|(q~0(i~oja$c28AQYh#K9e#T2Y8{ddLYos<1jPwr87JDA|t7035{( z6+7n$oR32Z-hwlguQFbKD{K&UMW6H-BY&oR?u&EYY8PbifrkW*8>_x~|#IlK}r_Pl7K>ma87do$e9bZpAK5q1c22^r6FFV7;bRHoV5z z^3PlF$gk-tv#}U@u}o-URRi8+JjZOS$Sx~?Qr-c_^Fze>Ny!N`sWy(NvqNtT^=NkW zrn1W1*AG2IwD(w9rqUN9N;OT#{(>z*3d8DkX_|?0EzL8HikuU<1-ZLMO}t@z*rk+D zW6gwbl~D9}N!FtuO|C(QefH?E^*A9ff)(aVDJ*)6fRK4(%MA5xyr$6$2B-t-KZ|+U2k5mghO_qcEV^d}d2!1)7E8Z@(C|gF5P_Ij9D5+RAPS1PL4I87p$(@S~&K#W@rTB)C(+tX}HH z;y$$?f@t`c9*#|z)$X~2ibP&p#NW{J-=HG3(qw6fI^_6K@*gfsI|o)A4IDx{A}-v; z!_t&lsJwdaG3V864IEi@q9Y$!rkP5!`xT7qQrAu@tRvmFs!I2e=3j_|`z`DRRZ!px zmrK`D4V%#npb74Q>qlT zYSgR|yR=4(2uk?8=e*xP@A>X??)!S4|E}kp=f2J_$;9X$JL_du006+QtAjAT(D93Q zVrIOUU(%i#T?oCermi{jMTIguCtloHymgSi001!Q@1{}i?XS5w2FOOuz$u z)8ZimtC)@*XosdkLU@MtY2?$5j*o%4hs%Srqv`?3seH$^!EKjq+0ZuU&)d&^Ib5++ z3h~w^{cB5&vOA}{Yg66sEnb6Xfge@U%T_gf#Xy@{E?^*lh1 zj4rQ_6s@HQsRqQ&Y}GQRJ-P*?r)3-8DeYR`)xlse%YvjEIEGW7x)bD+!Sw$A_Z8ZgCdKjd**!@NAkUb&?3Zah$arwnR zO=Ro*$8#>j?K%t24B1&@ZD+;*dFO`;$HVi-k|%P<9$gczhs zi1aNWTi6DFzU7zb`vBpDa;9{&p#@L99z{)mqhI4STRcAVnZk5yHOypqcxjP)&Oy^3 zn0g0O8!0cf^%q~LUIJY0WwpJr25(T^qbel=*fLDwD6Mq!@ssJSjHs$wjovx+NZ*N@ zu(}yc*{55c*PPS-$ggXo%`l)mtW(O5M)#RZl!)xX{0bFIjm+H^mb|mefB~G|%ro{`hP1}i} z(9R8!9}niTTm1%O{Z}NKf7s?dsO@rMCd~)l@7B!%j%sFmV6->DFXM(yVJiA|n{YF? zw$0SbbFs%t7MSK46)fX(g0m&XN+Js*h{c=t(){p0mj{}@f*x*devtuxd&bv3*G(N+t`qG&en*MD+|Y28unY&cJV_M(j*JGl7hPT zoLxhVs1n*@0{vof%41^txm?iRM?+Ruj#r9szcZ3YwZuYN(v!)CK_EM}(pWuNva_@? z?i5-UUd+ZVNJ+|Uu-_0S2{G=lN!1bTP*nw%A)Y9HTkt`GfZ7{}9S{5;i)!`tbi`0T0;m;;{^oMKU*m%V9JLc9C zrO>={nhd>m*x~Ig>Jg^|ugKRB5yYB&n0off^s$L?*bM#^G?eHn3IWa9C1lmnrRtiY zB*~h<-<&6VDuoFgaM8^A)IZ1Z&Cj9=A)RCs8u*A%V3AuF6u}_`Cyxe;UT)K9XcZFX zObGtXv*aL@Fg-i=Aw#ra?~Oydz3Th!r?72x zh$6e8v3gQNLIlU;CI%q6PX~b|KkK-OHnM(#3KY6nbu~+`UDF`1k0Lepr3Y~cssLX> zLt35o4i)CU`p^b=+aZFX;S1eKv6MnncCx+#qgKUvb6{&Bw$?ue5u+$=bl%c$*#UF4 z@1At}qIPeYJFSp9)Rw^4=c&#&(j}*uX08cOj?LKf7k<*s#F_HxwvYLwr2Q+Q&+y4s z$y5Isl;91HmnHp%{Bk3=w1mxjC;mdH-HN^w^2^~#}z2VfC$yFG#Sg?hEH zj<}v@^RbAKiLzO<=feyq&BN7KM^LN&6yxOB5i&W`jXLVPMtif6t>_gJNUD+YXQ)i5 ze!W6uy1$<@xrn$4_Q8qdP=-=Bb}vpZGgOh(N&+P#LS|f3YOVHnqg*0Ta^Q zj!G?`D|9sH6Kau@@PI$~C%_}{RT=ZMt@CI;mcz55eA&;x->Kxg+h|m;X2%~G7h4iF zvwv>CwH6IKI7Z>xcoCAaQC**bpRyvJ04++z{SaxVlf%9A_!5jrQL#jM&}L2x^~Q5y zuY$hDr+0WcAk7~J)6X(%WMDQco<)@l%}Y?N-(r0hM9tL~@=Uc=u4Gvr+O6w#T5Fi= zG&&9vRhA9MikHC->@rtK1pTcdV|c?fqcWuAkFESctN<}@ z1_OI3N;*$@wfjkto~NA}sab9ddjx}ui^c9?h;xfr)h?zzd+CF(VUQV8j~P_9*Io?# zqy45Y$0k1WdT67r7^jy?Qcu*Sg}Rw|XB(+%k$Xj_WtaurEoEa;yu{nnT56^!k8BG| zQher)=Ui@+vL0-XdA{@@Q3%Esvc+R{&%*!f(k;8lLU^Z>&hZc&MwM|APlW_DU#T!* zZu)hZXWk!-8~y9Y!4}8`d(MDwi2jyvCH`OAZRj_8 z?$@W~F@IT+TEwXV`x5u=q`r_)H9K#yVQrPLt*4IzJ|kzjXUH|0)Q7CqMHX8*K2~wu z4Z5MWlHyh_;L}#Zmm|oRGqdRkVxOvS&f^;K?)ZQ3CCxvu=Pmq8e<|Z18vC1QkO1d! z`o$-WYVRzr5oVboerxcd482Y#`F7OEs)5D0xila5u>6}cSB)C0caP>?E-ft`FL$R1 zqVd+pI!AxTX+r2}TWq$yMPuO#&keSw@tC!Ec0tOgauZKt%Q4EuWwq3OwA8NGWVQDF zdx7limN#qOeoE#xO&;HyE>JIKn6t9_RT)7NfSWt_@rjWYcQrm<0&oGaNGPzifEFNN z2N@_~AMp;P^c4F?xKs^v@gVMUMJ`nQnbH1lA~WF91YpNVimyA}$pw*S_-_6&lFx*s cFQoXKPDixCqJmsDdx6jZU2P*ottKk^zuFwzC-f)GmRf>MIi#CWJ7^j;!G z%ArURkjja7gZ006KVJk*6=@Wch2 zm@i-CzPFjC7sTKPF@P~&#B1hf@fSUd&qHfJ005Zqzo1j@A1ns|u2>uB-iHO}ZOFwMU>@?ta*JX3jE>=+^6zlX?OVCyDl7vWBQxf1TUjIXHYfUP+bQ zELbs3Y_H@Wc`~x28UAAHEq2ZYOI9V+Gt22Kktf|oY?8o%cg7le=)TjLbQpf%^}!u0 zLQYd^v{@fs($LoWWurqquj)u>fNOJk*$PBh!Ntv@84TiCc&{=31+Zt^rgEz?)#{*K zXMUuvqbn}8`PM_@9}F;IE{6zAQ>gD)(8H>3JXLfo8634ssr`fa^_X;xiDQ`swuc{3 zAT;}yo9hBLYpb-ENzx`&n?;UKcvKA|KD*Zy@a(cAio>rqb#IcDdj#f^#=pW188TtZ z7Bu+{E6Z{tz3#yq<<))mHrCdcA(@3{C>X2@7C4N1&MP^ zN%<@U=m#l?r6pn57+KUP=i?N^FC5julpSN9_NkjWnXMlEA~p+H*cqUBWOTb>nodRK zv(XGVYoj#rTscQxFO;aUsZ%a`MbgX2y8|=Q| z->d*eaU4kCxNbOcfyHhVr6PnNy0^SDTR5CB5-^CaF+@_g`@a;k7FcL_iyQw*)R9WL z%RiZw+KQM2e8v5qvil=DG`h{=J?v`++Pc2j70pFnpd8|UjA73YmG>_?=i1oFU2JRU zvd$#5-P`S5@!GIyY$IK2J9a6FJbBByRHM!-sHZ1DwPfgn%?-T)3i$Buy;2SU-vU3kkD|fXglsSaA z;LAzM2uAlPA%3Z&@m)FJnd0ic)|!-cpt4!$NVE#s(XOHhXbyXzvr@5u3Y|iyYsE1+ z0@5kl64pa|x1&-{M>#9Ih+ByzxggzsFfW+s$+$PO`>(*41B#|nnTG`h$wUoDI=tHY ziA=2hefsY-sM`)E4ckGB=*YO`fq#vYaFN#b9&y|Z?cq|i2=bD{OOv~7SDjM8TwtQF z;+__5kRY$%b7_-WTOt0Zypm_9yn=caEY;eXI8bU_Vqh<8QN9POBB@em)9}@dArc3AHn0nM$5&peMUfxIgV}5H`%K^Sl89*Tw!Mw>}Rj4+^+mZQptm`5Wtg zbMAbRP{HFQg>F8(t`e#0t3uP3jt!bCHlOa-vWmc$51y#r^Sw4s+1aY_@`PYRJC`e= zSTYJ!B#&dgq_^894gR6GFX$L*@J1`dA9i*gpEKK)C7g^U@?n+(#oVDD6n6D<}mTu(^QCRC<)T zIYBm~icpqlyO^OCe9(MXteBz4H@sqZ#p$*ABP`>j)WM^H#waQ5tA0y zMpe7-3m%vE6N(2y^q|4&fw*D2MAd!P=dK*Y0#0I}&`xjpVhbrK^x;BKC4-?f2<=$l zDzmPkC2=+y)|9LHrZ$|r<;c^2+&8{&Or~7LV-lD1c-3AlkfOyU{0h;#;ivycYPmx6 zcVOL;!^u+H!84dy27Vux1BXPVkXalxBVO1?yW7MjT0Z>@@ZJoZ%`=-?Vpw%O*VeB{ zF#lwM3DUFZEIipzraq_fqu^pO?s+CDoS)`dDuYZjdjjX*A)T&8v@P=hM?aD%m7@f| z3(+`e95CZJ&{c~ec*szz###U$g3sOLDBn@?57x1N%gucGEQ1D9e;R44;;nz(!S?qX z*7lCt^f1R&&cv_MDQ3h!0;gm8`vVg-&wnU~(W&3lJ>D2(tgPRqaPwvbZ!TXkBvGge zjrowF@sCYsMq2yaU65QN;G~V+{6Lmsc5#o78v+Bf@?!fkLm0zbFfSo|wVUst%lM4R z7=I)tE@=BG%h@|E{1oTg0E@o|ya8)zW_0;!l?PN_%=2@2-by|`zT)p(CI0!2QsVYz z3|;^h7Af3+6p!39Qpvq7ej&@MgwFkNX0cw&yD%{C=VpK4JOcUVfQnQ(!hlrujyJsJ z=K89LbEGBQo>v|Zz9sg_%!_XW6O5bwjW7Db&fQL3gk=|)IGu75QHB!}KkY*`E+lSl z^qwBh9bF)Ds@YkI>1+!qSiIEDa-Poq)BfP4Q>(Y0;%Zx!Wg@=)B(zJ}v8V0KYER8q zj}ejaNVo6?ZodI3!5yD7WT&O>6Lp9YS=u~QuAinkX{p1`Ssr9 z9bfsH6I51NP0YZ|EAeIHH}%fqsT1CPdMtjKQKTTm-bYY-O^hKQsr;ekq#iZS*p}6a ziD{X!swDnmEqZy8*&uh&6 zNSceMnj&_URn7$=1Z7vl{QYFdzMgw`ARi=a6;f!pWFIDkcT;7cTh|ZIu|`Vj#$*KK zKu_9tqjjT5GL8QfeF-!($}K&~m37uUcopS%@4gRQYxU^!gV5_MA#1h6opY~M=j*ZB zGG4uhf$1l!a}2WQcsmjO_^1JO%80-z@$JV+LJu{41TfY3x}^|JN>=`9*A)5d-@mgk zx3@Z2wn!ip9oQkp#`ki|k@Vp-&}Y&+YFf>B()=rXIQCazN=>++80#%6%H}$Q#O|5e zI#wg1@!<08V9NS*im*p zF8s|as!3jw@={)?W(y)<9{6M3(}}~c4d{2s{FFS1Vp6{oMnrhla}-;RJxElNi*KjM zU2KkE&45@=KDYYaTV`g62>GylEzs30M7$a#9lvszPUuO&bf*jmYE}o!B+g}^o*4fJ zUqQbgumjQ6H+b~_t;gNwO#Q8J+)H@Y{1w-p>eO#b0{V`1-F`1u+w}+C$j{&p8J0>PT?Im2aa!BCb=7f`-+Nuu z6d5gWhEQo3Jj|Iw5Ev;rX<@inF#DP+s+AFW8K{)-m4lq(pkutJCz< ziyiQfcBhQ9hh1NjO`#63*Mb2tzBkk`&N<4!859_?#05*}y+9uTpC>1tq`DiYte`oh4egEPW={KtL zdKnR*&0WP+LN6!*|8eNt-$pV?TSuQnPD){LzNU2pHbD1Y93+FmP3+yRtg)=gc0?$? eoylW@Mt@~Y3iou>m;d7P02n+l)vbWQqy7hoXjFax literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_pressed_light.9.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_pressed_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..972962dcfd074526eb79aebfe5e849266d256693 GIT binary patch literal 3384 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 O0000NdP)Zye`!#((c+X7)yM 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 I0NzLcAKv4MFaQ7m literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/ic_plusone_tall_off_client.png b/pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/ic_plusone_tall_off_client.png new file mode 100644 index 0000000000000000000000000000000000000000..fab5a79b45147f4ff5459e2c487ef237f111e674 GIT binary patch literal 6204 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 + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_icon_light.xml b/pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_icon_light.xml new file mode 100644 index 0000000000..abf412bda8 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_icon_light.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_text_dark.xml b/pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_text_dark.xml new file mode 100644 index 0000000000..2d92217cdf --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_text_dark.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_text_light.xml b/pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_text_light.xml new file mode 100644 index 0000000000..810c02112d --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_text_light.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-af/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-af/strings.xml new file mode 100644 index 0000000000..1b211f5076 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-af/strings.xml @@ -0,0 +1,31 @@ + + + "Kry Google Play-dienste" + "Hierdie program sal nie loop sonder Google Play-dienste nie, wat nie op jou foon is nie." + "Hierdie program sal nie loop sonder Google Play-dienste nie, wat nie op jou tablet is nie." + "Kry Google Play-dienste" + "Aktiveer Google Play-dienste" + "Hierdie program sal nie werk tensy jy Google Play-dienste aktiveer nie." + "Aktiveer Google Play-dienste" + "Dateer Google Play-dienste op" + "Hierdie program sal nie loop nie, tensy jy Google Play-dienste opdateer." + "Netwerkfout" + "\'n Dataverbinding is nodig om aan Google Play-dienste te koppel." + "Ongeldige rekening" + "Die gespesifiseerde rekening bestaan nie op hierdie toestel nie. Kies asseblief \'n ander rekening." + "Onbekende probleem met Google Play-dienste." + "Google Play-dienste" + "Google Play-dienste, waarop sommige van jou programme staatmaak, werk nie met jou toestel nie. Kontak asseblief die vervaardiger vir bystand." + "Dit lyk of die datum op die toestel verkeerd is. Gaan asseblief die datum op die toestel na." + "Dateer op" + "Meld aan" + "Meld aan met Google" + + "\'n Program het probeer om \'n slegte weergawe van Google Play-dienste te gebruik." + "\'n Program vereis dat Google Play-dienste geaktiveer word." + "\'n Program vereis dat Google Play-dienste geïnstalleer word." + "\'n Program vereis \'n opdatering vir Google Play-dienste." + "Google Play-dienstefout" + "Versoek deur %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-am/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-am/strings.xml new file mode 100644 index 0000000000..2585210fe0 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-am/strings.xml @@ -0,0 +1,31 @@ + + + "Google Play አገልግሎቶችን አግኝ" + "ይህ መተግበሪያ ያለ Google Play አገልግሎቶች አይሰራም፣ እነሱ ደግሞ ስልክዎ ላይ የሉም።" + "ይህ መተግበሪያ ያለ Google Play አገልግሎቶች አይሰራም፣ እነሱ ደግሞ ጡባዊዎ ላይ የሉም።" + "Google Play አገልግሎቶችን አግኝ" + "Google Play አገልግሎቶችን አንቃ" + "Google Play አገልግሎቶችን እስካላነቁ ድረስ ይህ መተግበሪያ አይሰራም።" + "Google Play አገልግሎቶችን አንቃ" + "Google Play አገልግሎቶችን ያዘምኑ" + "Google Play አገልግሎቶችን እስኪያዘምኑ ድረስ ይህ መተግበሪያ አይሰራም።" + "የአውታረ መረብ ስህተት" + "ከGoogle Play አገልግሎቶች ጋር ለመገናኘት የውሂብ ግንኙነት ያስፈልጋል።" + "ልክ ያልሆነ መለያ" + "የተገለጸው መለያ በዚህ መሣሪያ ላይ የለም። እባክው የተለየ መለያ ይምረጡ።" + "በGoogle Play አገልግሎቶች ላይ ያልታወቀ ችግር።" + "Google Play አገልግሎቶች" + "የGoogle Play አገልግሎቶች፣ አንዳንድ መተግበሪያዎችዎ በእሱ ላይ ጥገኛ የሆኑት፣ በመሣሪያዎ አይደገፍም። እባክዎ ለእርዳታ አምራቹን ያግኙ።" + "በመሣሪያው ላይ ያለው ቀን ትክክል አይመስልም። እባክዎ በመሣሪያው ላይ ያለውን ቀን ያረጋግጡ።" + "ያዘምኑ" + "ግባ" + "በGoogle ይግቡ" + + "መተግበሪያው የGoogle Play አገልግሎቶችን መጥፎ ስሪት ለመጠቀም ሞክሯል።" + "መተግበሪያው Google Play አገልግሎቶች እንዲነቁ ይፈልጋል።" + "መተግበሪያው Google Play አገልግሎቶች እንዲጫኑ ይፈልጋል።" + "መተግበሪያው Google Play አገልግሎቶች እንዲዘምን ይፈልጋል።" + "የGoogle Play አገልግሎቶች ስህተት" + "በ%1$s የተጠየቀ" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-ar/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-ar/strings.xml new file mode 100644 index 0000000000..bbc10b71fa --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-ar/strings.xml @@ -0,0 +1,31 @@ + + + "الحصول على خدمات Google Play" + "لن يتم تشغيل هذا التطبيق بدون خدمات Google Play، والتي لا تتوفر في هاتفك." + "لن يتم تشغيل هذا التطبيق بدون خدمات Google Play، والتي لا تتوفر في جهازك اللوحي." + "الحصول على خدمات Google Play" + "تمكين خدمات Google Play" + "لن يعمل هذا التطبيق ما لم يتم تمكين خدمات Google Play." + "تمكين خدمات Google Play" + "تحديث خدمات Google Play" + "لن يتم تشغيل هذا التطبيق ما لم تحدِّث خدمات Google Play." + "خطأ في الشبكة" + "يتطلب الاتصال بخدمات Google Play وجود اتصال بيانات." + "حساب غير صالح" + "الحساب الذي تمّ تحديده غير موجود على الجهاز. يُرجى اختيار حساب آخر." + "حدثت مشكلة غير معروفة في خدمات Google Play." + "خدمات Google Play" + "خدمات Google Play التي تستجيب لها بعض تطبيقاتك لا تعمل على جهازك. يُرجى الاتصال بجهة التصنيع للحصول على المساعدة." + "يبدو أن التاريخ على الجهاز غير صحيح. الرجاء التحقق من التاريخ على الجهاز." + "تحديث" + "تسجيل الدخول" + "تسجيل الدخول باستخدام Google" + + "يحاول أحد التطبيقات استخدام إصدار غير صالح من خدمات Google Play." + "يتطلب أحد التطبيقات تمكين خدمات Google Play." + "يتطلب أحد التطبيقات تثبيت خدمات Google Play." + "يتطلب أحد التطبيقات تحديث خدمات Google Play." + "خطأ في خدمات Google Play" + "تم الطلب عن طريق %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-be/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-be/strings.xml new file mode 100644 index 0000000000..81382d1c0f --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-be/strings.xml @@ -0,0 +1,36 @@ + + + "Атрымаць службы Google Play" + "Гэта прыкладанне не будзе працаваць без службаў Google Play, якіх няма ў вашым тэлефоне." + "Гэта прыкладанне не будзе працаваць без службаў Google Play, якіх няма на вашым планшэце." + "Атрымаць службы Google Play" + "Уключыць службы Google Play" + "Гэта прыкладанне не будзе працаваць, пакуль вы не ўключыце службы Google Play." + "Уключыць службы Google Play" + "Абнаўленне службаў Google Play" + "Гэта прыкладанне не будзе працаваць падчас абнаўлення службаў Google Play." + + + + + + + + + "Невядомая праблема са службамі Google Play." + "Службы Google Play" + "Службы Google Play, да якiх прывязаны некаторыя прыкладаннi, не падтрымлiваюцца на вашай прыладзе. Па дапамогу звярнiцеся да вытворцы." + + + "Абнавіць" + "Увайсцi" + "Увайсці ў Google" + + "Прыкладанне паспрабавала скарыстацца сапсаванай версіяй службаў Google Play." + "Прыкладанне патрабуе ўключэння службаў Google Play." + "Прыкладанне патрабуе ўсталявання службаў Google Play." + "Прыкладанне патрабуе абнаўлення службаў Google Play." + "Памылка службаў Google Play" + "Запытана прыкладаннем %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-bg/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-bg/strings.xml new file mode 100644 index 0000000000..bb8da3c105 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-bg/strings.xml @@ -0,0 +1,31 @@ + + + "Изтегляне на услугите за Google Play" + "Това приложение няма да се изпълнява без услугите за Google Play, които липсват в телефона ви." + "Това приложение няма да се изпълнява без услугите за Google Play, които липсват в таблета ви." + "Услуги за Google Play: Изтегл." + "Активиране на услугите за Google Play" + "Това приложение няма да работи, освен ако не активирате услугите за Google Play." + "Услуги за Google Play: Актив." + "Актуализиране на услугите за Google Play" + "Това приложение няма да се изпълнява, освен ако не актуализирате услугите за Google Play." + "Грешка в мрежата" + "За свързване с услугите за Google Play се изисква връзка за данни." + "Невалиден профил" + "Посоченият профил не съществува на това устройство. Моля, изберете друг." + "Неизвестен проблем с услугите за Google Play." + "Услуги за Google Play" + "Услугите за Google Play, на които разчитат някои от приложенията ви, не се поддържат от устройството ви. Моля, свържете се с производителя за помощ." + "Изглежда, че датата на устройството е неправилна. Моля, проверете я." + "Актуализиране" + "Вход" + "Вход с Google" + + "Приложение опита да ползва неправилна версия на услуг. за Google Play." + "Приложение изисква активирането на услугите за Google Play." + "Приложение изисква инсталирането на услугите за Google Play." + "Приложение изисква актуализирането на услугите за Google Play." + "Грешка в услугите за Google Play" + "Заявено от %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-ca/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-ca/strings.xml new file mode 100644 index 0000000000..5b63e86af7 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-ca/strings.xml @@ -0,0 +1,31 @@ + + + "Baixa els serveis de Google Play" + "Aquesta aplicació no s\'executarà si el telèfon no té instal·lats els serveis de Google Play." + "Aquesta aplicació no funcionarà si la tauleta no té instal·lats els serveis de Google Play." + "Baixa els serveis de Google Play" + "Activa els serveis de Google Play" + "Aquesta aplicació no funcionarà si no actives els serveis de Google Play." + "Activa els serveis de Google Play" + "Actualitza els serveis de Google Play" + "Aquesta aplicació no s\'executarà si no actualitzes els serveis de Google Play." + "Error de xarxa" + "Es requereix una connexió de dades per connectar amb els serveis de Google Play." + "Compte no vàlid" + "El compte especificat no existeix en aquest dispositiu. Tria un compte diferent." + "Error desconegut relacionat amb els serveis de Google Play." + "Serveis de Google Play" + "El teu dispositiu no és compatible amb els serveis de Google Play, en què es basen les teves aplicacions. Per obtenir assistència, contacta amb el fabricant." + "Sembla que la data del dispositiu no és correcta. Comprova-la." + "Actualitza" + "Inicia sessió" + "Inicia sessió amb Google" + + "Una aplic. ha intentat utilitzar una versió errònia de serveis de Play." + "Una aplicació requereix que s\'activin els serveis de Google Play." + "Una aplicació requereix que s\'instal·lin els serveis de Google Play." + "Una aplicació requereix que s\'actualitzin els serveis de Google Play." + "Error dels serveis de Google Play" + "Sol·licitada per %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-cs/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-cs/strings.xml new file mode 100644 index 0000000000..1b5423b039 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-cs/strings.xml @@ -0,0 +1,31 @@ + + + "Instalovat služby Google Play" + "Ke spuštění této aplikace jsou potřeba služby Google Play, které v telefonu nemáte." + "Ke spuštění této aplikace jsou potřeba služby Google Play, které v tabletu nemáte." + "Instalovat služby Google Play" + "Aktivovat služby Google Play" + "Ke spuštění této aplikace je třeba aktivovat služby Google Play." + "Aktivovat služby Google Play" + "Aktualizace služeb Google Play" + "Ke spuštění této aplikace je třeba aktualizovat služby Google Play." + "Chyba sítě" + "Připojení ke službám Google Play vyžaduje datové připojení." + "Neplatný účet" + "Zadaný účet v tomto zařízení neexistuje. Zvolte prosím jiný účet." + "Nastal neznámý problém se službami Google Play." + "Služby Google Play" + "Některé vaše aplikace vyžadují služby Google Play, které ve vašem zařízení nejsou podporovány. S žádostí o pomoc se prosím obraťte na výrobce." + "Datum v zařízení není správně nastaveno. Zkontrolujte prosím datum." + "Aktualizovat" + "Přihlásit se" + "Přihlásit se účtem Google" + + "Aplikace se pokusila použít nesprávnou verzi Služeb Google Play." + "Aplikace vyžaduje aktivované Služby Google Play." + "Aplikace vyžaduje instalaci Služeb Google Play." + "Aplikace vyžaduje aktualizaci Služeb Google Play." + "Chyba služeb Google Play" + "Požadováno aplikací %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-da/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-da/strings.xml new file mode 100644 index 0000000000..daa2160d3b --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-da/strings.xml @@ -0,0 +1,31 @@ + + + "Hent Google Play-tjenester" + "Denne app kan ikke køre uden Google Play-tjenester, som mangler på din telefon." + "Denne app kan ikke køre uden Google Play-tjenester, som mangler på din tablet." + "Hent Google Play-tjenester" + "Aktivér Google Play-tjenester" + "Denne app virker ikke, medmindre du aktiverer Google Play-tjenester." + "Aktivér Google Play-tjenester" + "Opdater Google Play-tjenester" + "Denne app kan ikke køre, medmindre du opdaterer Google Play-tjenester." + "Netværksfejl" + "Der kræves en dataforbindelse for at oprette forbindelse til Google Play-tjenester." + "Ugyldig konto" + "Den angivne konto findes ikke på denne enhed. Vælg en anden konto." + "Ukendt problem med Google Play-tjenester." + "Google Play-tjenester" + "Google Play-tjenester, som nogle af dine applikationer er afhængige af, understøttes ikke af din enhed. Kontakt producenten for at få hjælp." + "Datoen på enheden ser ud til at være forkert. Husk at kontrollere datoen på enheden." + "Opdater" + "Log ind" + "Log ind med Google" + + "En applikation forsøgte at bruge en defekt version af Google Play." + "En applikation kræver, at Google Play er aktiveret." + "En applikation kræver, at Google Play er installeret." + "En applikation kræver en opdatering af Google Play." + "Fejl i Google Play-tjenester" + "Anmodning fra %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-de/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-de/strings.xml new file mode 100644 index 0000000000..ef6d779eff --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-de/strings.xml @@ -0,0 +1,31 @@ + + + "Google Play-Dienste installieren" + "Zur Nutzung dieser App sind Google Play-Dienste erforderlich, die auf Ihrem Telefon nicht installiert sind." + "Zur Nutzung dieser App sind Google Play-Dienste erforderlich, die auf Ihrem Tablet nicht installiert sind." + "Google Play-Dienste installieren" + "Google Play-Dienste aktivieren" + "Diese App funktioniert nur, wenn Sie die Google Play-Dienste aktivieren." + "Google Play-Dienste aktivieren" + "Google Play-Dienste aktualisieren" + "Diese App wird nur ausgeführt, wenn Sie die Google Play-Dienste aktualisieren." + "Netzwerkfehler" + "Um eine Verbindung zu den Google Play-Diensten herzustellen, ist eine Datenverbindung erforderlich." + "Ungültiges Konto" + "Das angegebene Konto ist auf diesem Gerät nicht vorhanden. Bitte wählen Sie ein anderes Konto aus." + "Unbekanntes Problem mit Google Play-Diensten" + "Google Play-Dienste" + "Google Play-Dienste, auf denen einige Ihrer Apps basieren, werden von diesem Gerät nicht unterstützt. Wenden Sie sich für weitere Informationen an den Hersteller." + "Das Datum auf dem Gerät scheint falsch zu sein. Bitte überprüfen Sie das Datum auf dem Gerät." + "Aktualisieren" + "Anmelden" + "Über Google anmelden" + + "Anwendung versuchte, defekte Google Play-Dienste-Version zu verwenden" + "Anwendung erfordert aktivierte Google Play-Dienste" + "Anwendung erfordert die Installation von Google Play-Diensten" + "Anwendung erfordert ein Update für Google Play-Dienste" + "Fehler bei Google Play-Diensten" + "Angefordert von %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-el/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-el/strings.xml new file mode 100644 index 0000000000..13a5dc5ef3 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-el/strings.xml @@ -0,0 +1,31 @@ + + + "Λήψη υπηρεσιών Google Play" + "Αυτή η εφαρμογή δεν θα εκτελεστεί χωρίς τις υπηρεσίες Google Play, οι οποίες λείπουν από το τηλέφωνό σας." + "Αυτή η εφαρμογή δεν θα εκτελεστεί χωρίς τις υπηρεσίες Google Play, οι οποίες λείπουν από το tablet σας." + "Λήψη υπηρεσιών Google Play" + "Ενεργοποίηση υπηρεσιών Google Play" + "Αυτή η εφαρμογή δεν θα λειτουργήσει εάν δεν έχετε ενεργοποιήσει τις υπηρεσίες Google Play." + "Ενεργοπ. υπηρεσιών Google Play" + "Ενημέρωση υπηρεσιών Google Play" + "Αυτή η εφαρμογή θα εκτελεστεί αφού ενημερώσετε τις υπηρεσίες Google Play." + "Σφάλμα δικτύου" + "Απαιτείται σύνδεση δεδομένων για να συνδεθείτε με τις Υπηρεσίες Google Play." + "Μη έγκυρος λογαριασμός" + "Ο συγκεκριμένος λογαριασμός δεν υπάρχει σε αυτήν τη συσκευή. Επιλέξτε έναν διαφορετικό λογαριασμό." + "Άγνωστο πρόβλημα με τις υπηρεσίες Google Play." + "Υπηρεσίες Google Play" + "Οι υπηρεσίες Google Play, στις οποίες βασίζονται ορισμένες από τις εφαρμογές σας, δεν υποστηρίζονται στη συσκευή σας. Επικοινωνήστε με τον κατασκευαστή για υποστήριξη." + "Η ημερομηνία στη συσκευή φαίνεται λανθασμένη. Ελέγξτε την ημερομηνία στη συσκευή." + "Ενημέρωση" + "Σύνδεση" + "Συνδεθείτε στο Google" + + "Απόπειρα χρήσης ακατάλληλης έκδοσης Υπηρεσιών Google Play από εφαρμογή" + "Μια εφαρμογή απαιτεί τις Υπηρεσίες Google Play για ενεργοποίηση." + "Μια εφαρμογή απαιτεί την εγκατάσταση των Υπηρεσιών Google Play." + "Μια εφαρμογή απαιτεί μια ενημέρωση για τις Υπηρεσίες Google Play." + "Σφάλμα υπηρεσιών Google Play" + "Υποβλήθηκε αίτημα από την εφαρμογή %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-en-rGB/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-en-rGB/strings.xml new file mode 100644 index 0000000000..106d390b3e --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-en-rGB/strings.xml @@ -0,0 +1,31 @@ + + + "Get Google Play services" + "This app won\'t run without Google Play services, which are missing from your phone." + "This app won\'t run without Google Play services, which are missing from your tablet." + "Get Google Play services" + "Enable Google Play services" + "This app won\'t work unless you enable Google Play services." + "Enable Google Play services" + "Update Google Play services" + "This app won\'t run unless you update Google Play services." + "Network Error" + "A data connection is required to connect to Google Play services." + "Invalid Account" + "The specified account does not exist on this device. Please choose a different account." + "Unknown issue with Google Play services." + "Google Play services" + "Google Play services, which some of your applications rely on, is not supported by your device. Please contact the manufacturer for assistance." + "The date on the device appears to be incorrect. Please check the date on the device." + "Update" + "Sign in" + "Sign in with Google" + + "An application attempted to use a bad version of Google Play Services." + "An application requires Google Play Services to be enabled." + "An application requires installation of Google Play Services." + "An application requires an update for Google Play Services." + "Google Play services error" + "Requested by %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-en-rIN/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-en-rIN/strings.xml new file mode 100644 index 0000000000..106d390b3e --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-en-rIN/strings.xml @@ -0,0 +1,31 @@ + + + "Get Google Play services" + "This app won\'t run without Google Play services, which are missing from your phone." + "This app won\'t run without Google Play services, which are missing from your tablet." + "Get Google Play services" + "Enable Google Play services" + "This app won\'t work unless you enable Google Play services." + "Enable Google Play services" + "Update Google Play services" + "This app won\'t run unless you update Google Play services." + "Network Error" + "A data connection is required to connect to Google Play services." + "Invalid Account" + "The specified account does not exist on this device. Please choose a different account." + "Unknown issue with Google Play services." + "Google Play services" + "Google Play services, which some of your applications rely on, is not supported by your device. Please contact the manufacturer for assistance." + "The date on the device appears to be incorrect. Please check the date on the device." + "Update" + "Sign in" + "Sign in with Google" + + "An application attempted to use a bad version of Google Play Services." + "An application requires Google Play Services to be enabled." + "An application requires installation of Google Play Services." + "An application requires an update for Google Play Services." + "Google Play services error" + "Requested by %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-es-rUS/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-es-rUS/strings.xml new file mode 100644 index 0000000000..6be905908c --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-es-rUS/strings.xml @@ -0,0 +1,31 @@ + + + "Obtener Google Play Services" + "Esta aplicación no se ejecutará si no instalasGoogle Play Services en tu dispositivo." + "Esta aplicación no se ejecutará si no instalas Google Play Services en tu tablet." + "Descargar Google Play Services" + "Activar Google Play Services" + "Esta aplicación no funcionará si no activas Google Play Services." + "Activar Google Play Services" + "Actualizar Google Play Services" + "Esta aplicación no se ejecutará si no actualizas Google Play Services." + "Error de red" + "Se necesita una conexión de datos para establecer conexión con Google Play Services." + "Cuenta no válida" + "La cuenta especificada no existe en este dispositivo. Elige otra cuenta." + "Error desconocido relacionado con Google Play Services" + "Google Play Services" + "Google Play Services, del cual dependen algunas de tus aplicaciones, no es compatible con tu dispositivo. Comunícate con el fabricante para obtener ayuda." + "Parece que la fecha del dispositivo es incorrecta. ¿Puedes revisarla?" + "Actualizar" + "Acceder" + "Acceder con Google" + + "Una aplic. intentó usar una versión no válida de Google Play Services" + "Una aplicación requiere que se active Google Play Services" + "Una aplicación requiere que se instale Google Play Services" + "Una aplicación requiere que se actualice Google Play Services" + "Error de Google Play Services" + "Solicitada por %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-es/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-es/strings.xml new file mode 100644 index 0000000000..ed32995cf2 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-es/strings.xml @@ -0,0 +1,31 @@ + + + "Descargar servicios de Google Play" + "Esta aplicación no se ejecutará si tu teléfono no tiene instalados los servicios de Google Play." + "Esta aplicación no se ejecutará si tu tablet no tiene instalados los servicios de Google Play." + "Descargar servicios de Google Play" + "Habilitar servicios de Google Play" + "Esta aplicación no funcionará si no habilitas los servicios de Google Play." + "Habilitar servicios de Google Play" + "Actualizar servicios de Google Play" + "Esta aplicación no se ejecutará si no actualizas los servicios de Google Play." + "Error de red" + "Se necesita una conexión de datos para establecer conexión con los servicios de Google Play." + "Cuenta no válida" + "La cuenta especificada no existe en este dispositivo. Selecciona otra cuenta." + "Error desconocido relacionado con los servicios de Google Play" + "Servicios de Google Play" + "Tu dispositivo no es compatible con los servicios de Google Play, de los cuales dependen tus aplicaciones. Para obtener asistencia, ponte en contacto el fabricante." + "Parece que la fecha del dispositivo es incorrecta. Compruébala." + "Actualizar" + "Iniciar sesión" + "Iniciar sesión con Google" + + "Una aplicación intentó usar versión incorrecta de servicios de Google Play." + "Una aplicación requiere que se habiliten los servicios de Play." + "Una aplicación requiere que se instalen los servicios de Google Play." + "Una aplicación requiere que se actualicen los servicios de Google Play." + "Error de los servicios de Google Play" + "Solicitada por %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-et-rEE/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-et-rEE/strings.xml new file mode 100644 index 0000000000..281caff497 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-et-rEE/strings.xml @@ -0,0 +1,31 @@ + + + "Hankige Google Play teenused" + "Selle rakenduse käitamiseks on vaja Google Play teenuseid, mida teie telefonis pole." + "Selle rakenduse käitamiseks on vaja Google Play teenuseid, mida teie tahvelarvutis pole." + "Hankige Google Play teenused" + "Lubage Google Play teenused" + "See rakendus ei tööta, kui te ei luba Google Play teenuseid." + "Lubage Google Play teenused" + "Värskendage Google Play teenuseid" + "Seda rakendust ei saa käitada, kui te ei värskenda Google Play teenuseid." + "Võrgu viga" + "Google Play teenustega ühenduse loomiseks on vajalik andmesideühendus." + "Vale konto" + "Määratud kontot pole selles seadmes olemas. Valige muu konto." + "Google Play teenuste tundmatu probleem." + "Google Play teenused" + "Teie seade ei toeta Google Play teenuseid, millele mõni teie rakendustest toetub. Abi saamiseks võtke ühendust tootjaga." + "Seadme kuupäev paistab olevat vale. Kontrollige seadme kuupäeva." + "Värskenda" + "Logi sisse" + "Logi sisse Google\'iga" + + "Rakendus püüdis kasutada Google Play teenuste sobimatut versiooni." + "Rakenduse kasutamiseks peavad olema lubatud Google Play teenused." + "Rakenduse kasutamiseks peavad olema installitud Google Play teenused." + "Rakenduse kasutamiseks tuleb värskendada Google Play teenuseid." + "Viga Google Play teenustes" + "Päringu esitas: %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-et/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-et/strings.xml new file mode 100644 index 0000000000..281caff497 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-et/strings.xml @@ -0,0 +1,31 @@ + + + "Hankige Google Play teenused" + "Selle rakenduse käitamiseks on vaja Google Play teenuseid, mida teie telefonis pole." + "Selle rakenduse käitamiseks on vaja Google Play teenuseid, mida teie tahvelarvutis pole." + "Hankige Google Play teenused" + "Lubage Google Play teenused" + "See rakendus ei tööta, kui te ei luba Google Play teenuseid." + "Lubage Google Play teenused" + "Värskendage Google Play teenuseid" + "Seda rakendust ei saa käitada, kui te ei värskenda Google Play teenuseid." + "Võrgu viga" + "Google Play teenustega ühenduse loomiseks on vajalik andmesideühendus." + "Vale konto" + "Määratud kontot pole selles seadmes olemas. Valige muu konto." + "Google Play teenuste tundmatu probleem." + "Google Play teenused" + "Teie seade ei toeta Google Play teenuseid, millele mõni teie rakendustest toetub. Abi saamiseks võtke ühendust tootjaga." + "Seadme kuupäev paistab olevat vale. Kontrollige seadme kuupäeva." + "Värskenda" + "Logi sisse" + "Logi sisse Google\'iga" + + "Rakendus püüdis kasutada Google Play teenuste sobimatut versiooni." + "Rakenduse kasutamiseks peavad olema lubatud Google Play teenused." + "Rakenduse kasutamiseks peavad olema installitud Google Play teenused." + "Rakenduse kasutamiseks tuleb värskendada Google Play teenuseid." + "Viga Google Play teenustes" + "Päringu esitas: %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-fa/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-fa/strings.xml new file mode 100644 index 0000000000..4546e5747e --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-fa/strings.xml @@ -0,0 +1,31 @@ + + + "دریافت خدمات Google Play" + "این برنامه بدون خدمات Google Play اجرا نمی‌شود، این خدمات در تلفن شما وجود ندارد." + "این برنامه بدون خدمات Google Play اجرا نمی‌شود، این خدمات در رایانهٔ لوحی شما وجود ندارد." + "دریافت خدمات Google Play" + "فعال کردن خدمات Google Play" + "تا زمانی‌که خدمات Google Play را فعال نکنید این برنامه کار نمی‌کند." + "فعال کردن خدمات Google Play" + "به‌روزرسانی خدمات Google Play" + "تا زمانی‌که خدمات Google Play را به‌روز نکنید این برنامه کار نمی‌کند." + "خطای شبکه" + "برای اتصال به خدمات Google Play اتصال داده لازم است." + "حساب نامعتبر" + "حسابی که تعیین کردید در این دستگاه وجود ندارد. لطفاً حساب دیگری را انتخاب کنید." + "مشکل نامشخص در خدمات Google Play." + "خدمات Google Play" + "خدمات Google Play، که برخی از برنامه‌های شما به آن وابسته است، توسط دستگاه شما پشتیبانی نمی‌شود. لطفاً برای دریافت کمک با سازنده تماس بگیرید." + "تاریخ روی دستگاه ظاهراً اشتباه است. لطفاً تاریخ روی دستگاه را بررسی کنید." + "به‌روزرسانی" + "ورود به سیستم" + "ورود به سیستم با Google‎" + + "برنامه‌ای تلاش کرد از نسخه نادرستی از خدمات Google Play استفاده کند." + "برنامه‌ای به فعال کردن خدمات Google Play نیاز دارد." + "برنامه‌ای به نصب خدمات Google Play نیاز دارد." + "برنامه‌ای به به‌روزرسانی خدمات Google Play نیاز دارد." + "خطا در خدمات Google Play" + "درخواست توسط %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-fi/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-fi/strings.xml new file mode 100644 index 0000000000..00d3ceb215 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-fi/strings.xml @@ -0,0 +1,31 @@ + + + "Asenna Google Play -palvelut" + "Tämä sovellus ei toimi ilman Google Play -palveluita, jotka puuttuvat puhelimesta." + "Tämä sovellus ei toimi ilman Google Play -palveluita, jotka puuttuvat tablet-laitteesta." + "Asenna Google Play -palvelut" + "Ota Google Play -palvelut käyttöön" + "Tämä sovellus ei toimi, ellet ota Google Play -palveluita käyttöön." + "Ota Google Play -palv. käyttöön" + "Päivitä Google Play -palvelut" + "Tämä sovellus ei toimi, ellet päivitä Google Play -palveluita." + "Verkkovirhe" + "Google Play -palveluiden käyttöön tarvitaan tietoliikenneyhteys." + "Tili ei kelpaa" + "Kyseistä tiliä ei ole tällä laitteella. Valitse toinen tili." + "Tuntematon ongelma käytettäessä Google Play -palveluita." + "Google Play -palvelut" + "Google Play -palveluita, joita osa sovelluksistasi käyttää, ei tueta laitteellasi. Pyydä ohjeita laitteen valmistajalta." + "Laitteen päivämäärä vaikuttaa virheelliseltä. Tarkista laitteen päivämäärä." + "Päivitä" + "Kirjaudu" + "Kirjaudu Google-tiliin" + + "Sovellus yritti käyttää virheellistä Google Play -palveluiden versiota" + "Ota käyttöön Google Play -palvelut, jotta sovellus toimii." + "Asenna Google Play -palvelut, jotta sovellus toimii." + "Päivitä Google Play -palvelut, jotta sovellus toimii." + "Virhe Google Play -palveluissa" + "Pyynnön teki %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-fr-rCA/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-fr-rCA/strings.xml new file mode 100644 index 0000000000..e915fe4067 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-fr-rCA/strings.xml @@ -0,0 +1,31 @@ + + + "Installer les services Google Play" + "Cette application ne fonctionnera pas sans les services Google Play, qui ne sont pas installés sur votre téléphone." + "Cette application ne fonctionnera pas sans les services Google Play, qui ne sont pas installés sur votre tablette." + "Installer les services Google Play" + "Activer les services Google Play" + "Cette application ne fonctionnera pas tant que vous n\'aurez pas activé les services Google Play." + "Activer les services Google Play" + "Mettre à jour les services Google Play" + "Cette application ne fonctionnera pas tant que vous n\'aurez pas mis à jour les services Google Play." + "Erreur réseau" + "Vous devez disposer d\'une connexion de données pour utiliser les services Google Play." + "Compte erroné" + "Le compte indiqué n\'existe pas sur cet appareil. Veuillez sélectionner un autre compte." + "Problème inconnu avec les services Google Play." + "Services Google Play" + "Les services Google Play, dont dépendent certaines de vos applications, ne sont pas compatibles avec votre appareil. Veuillez contacter le fabricant pour obtenir de l\'aide." + "La date sur l\'appareil semble incorrecte. Veuillez la vérifier." + "Mettre à jour" + "Connexion" + "Se connecter via Google" + + "Une application requiert une version valide des services Google Play" + "Une application requiert l\'activation des services Google Play" + "Une application requiert l\'installation des services Google Play" + "Une application requiert la mise à jour des services Google Play" + "Erreur liée aux services Google Play" + "Demandée par %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-fr/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-fr/strings.xml new file mode 100644 index 0000000000..321b28370b --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-fr/strings.xml @@ -0,0 +1,31 @@ + + + "Installer les services Google Play" + "Cette application ne fonctionnera pas sans les services Google Play, qui ne sont pas installés sur votre téléphone." + "Cette application ne fonctionnera pas sans les services Google Play, qui ne sont pas installés sur votre tablette." + "Installer services Google Play" + "Activer les services Google Play" + "Cette application ne fonctionnera pas tant que vous n\'aurez pas activé les services Google Play." + "Activer services Google Play" + "Mettre à jour les services Google Play" + "Cette application ne fonctionnera pas tant que vous n\'aurez pas mis à jour les services Google Play." + "Erreur réseau" + "Vous devez disposer d\'une connexion de données pour utiliser les services Google Play." + "Compte erroné" + "Le compte indiqué n\'existe pas sur cet appareil. Veuillez sélectionner un autre compte." + "Problème inconnu avec les services Google Play." + "Services Google Play" + "Les services Google Play, dont dépendent certaines de vos applications, ne sont pas compatibles avec votre appareil. Veuillez contacter le fabricant pour obtenir de l\'aide." + "La date sur l\'appareil semble incorrecte. Veuillez la vérifier." + "Mettre à jour" + "Connexion" + "Se connecter avec Google" + + "Une application requiert une version valide des services Google Play" + "Une application requiert l\'activation des services Google Play" + "Une application requiert l\'installation des services Google Play" + "Une application requiert la mise à jour des services Google Play" + "Erreur liée aux services Google Play" + "Demandée par %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-hi/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-hi/strings.xml new file mode 100644 index 0000000000..e1b3b95707 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-hi/strings.xml @@ -0,0 +1,31 @@ + + + "Google Play सेवाएं पाएं" + "यह एप्स Google Play सेवाओं के बिना नहीं चलेगा, जो आपके फ़ोन में नहीं हैं." + "यह एप्स Google Play सेवाओं के बिना नहीं चलेगा, जो आपके टेबलेट में नहीं हैं." + "Google Play सेवाएं पाएं" + "Google Play सेवाएं सक्षम करें" + "जब तक आप Google Play सेवाएं सक्षम नहीं करते, तब तक यह एप्स कार्य नहीं करेगा." + "Google Play सेवाएं सक्षम करें" + "Google Play सेवाएं से नई जानकारी" + "जब तक आप Google Play सेवाओं से नई जानकारी नहीं लेते हैं, तब तक यह एप्स नहीं चलेगा." + "नेटवर्क त्रुटि" + "Google Play सेवाओं से कनेक्ट करने के लिए डेटा कनेक्शन की आवश्यकता है." + "अमान्य खाता" + "निर्दिष्ट खाता इस उपकरण पर मौजूद नहीं है. कृपया कोई भिन्न खाता चुनें." + "Google Play सेवाओं के साथ अज्ञात समस्या." + "Google Play सेवाएं" + "Google Play सेवाएं, जिन पर आपके कुछ एप्स निर्भर करते हैं, आपके उपकरण द्वारा समर्थित नहीं हैं. कृपया सहायता के लिए निर्माता से संपर्क करें." + "उपकरण का दिनांक गलत प्रतीत हो रहा है. कृपया उपकरण का दिनांक जांचें." + "नई जानकारी पाएं" + "प्रवेश करें" + "Google से प्रवेश करें" + + "एप्लि. ने Google Play सेवाओं के खराब संस्करण के उपयोग का प्रयास किया." + "एप्स के लिए Google Play सेवाओं को सक्षम किए जाने की आवश्यकता है." + "एप्स के लिए Google Play सेवाओं के इंस्टॉलेशन की आवश्यकता है." + "एप्स के लिए Google Play सेवाओं में Google Play से नई जानकारी की आवश्यकता है." + "Google Play सेवाएं त्रुटि" + "%1$s द्वारा अनुरोधित" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-hr/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-hr/strings.xml new file mode 100644 index 0000000000..b7d462d882 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-hr/strings.xml @@ -0,0 +1,31 @@ + + + "Preuzmi usluge za Google Play" + "Ova aplikacija neće funkcionirati bez usluga za Google Play, koje nisu instalirane na vašem telefonu." + "Ova aplikacija neće funkcionirati bez usluga za Google Play, koje nisu instalirane na vašem tabletnom računalu." + "Preuzmi usluge za Google Play" + "Omogući usluge za Google Play" + "Ova aplikacija neće raditi ako ne omogućite usluge za Google Play." + "Omogući usluge za Google Play" + "Ažuriraj usluge za Google Play" + "Ova se aplikacija neće pokrenuti ako ne ažurirate usluge za Google Play." + "Mrežna pogreška" + "Potrebna je podatkovna veza za povezivanje s uslugama Google Play." + "Nevažeći račun" + "Navedeni račun ne postoji na ovom uređaju. Odaberite neki drugi račun." + "Nepoznata poteškoća s uslugama za Google Play." + "Usluge za Google Play" + "Usluge za Google Play, koje su potrebne za funkcioniranje nekih vaših aplikacija, nisu podržane na vašem uređaju. Pomoć potražite od proizvođača." + "Čini se da datum na uređaju nije točan. Provjerite datum na uređaju." + "Ažuriranje" + "Prijava" + "Prijava uslugom Google" + + "Aplikacija je pokušala upotrijebiti lošu verziju Usluga za Google Play." + "Aplikacija zahtijeva omogućavanje Usluga za Google Play." + "Aplikacija zahtijeva instaliranje Usluga za Google Play." + "Aplikacija zahtijeva ažuriranje Usluga za Google Play." + "Pogreška usluga za Google Play" + "Zahtijeva aplikacija %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-hu/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-hu/strings.xml new file mode 100644 index 0000000000..cd15ad328f --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-hu/strings.xml @@ -0,0 +1,31 @@ + + + "Play Szolgáltatások telepítése" + "Az alkalmazás működéséhez a Google Play Szolgáltatások szükségesek, ezek nincsenek telepítve a telefonon." + "Az alkalmazás működéséhez a Google Play Szolgáltatások szükségesek, ezek nincsenek telepítve a táblagépen." + "Play Szolgáltatások telepítése" + "Google Play Szolgáltatások aktiválása" + "Az alkalmazás csak akkor fog működni, ha engedélyezi a Google Play Szolgáltatásokat." + "Play Szolgáltatások aktiválása" + "Play Szolgáltatások frissítése" + "Az alkalmazás csak akkor fog működni, ha frissíti a Google Play Szolgáltatásokat." + "Hálózati hiba" + "A Google Play Szolgáltatásokhoz történő kapcsolódáshoz adatkapcsolat szükséges." + "Érvénytelen fiók" + "A megadott fiók nem létezik ezen az eszközön. Kérjük, válasszon másik fiókot." + "Ismeretlen hiba a Google Play Szolgáltatásokban." + "Google Play Szolgáltatások" + "A Google Play Szolgáltatásokat, amelyre egyes alkalmazások támaszkodnak, nem támogatja az eszköz. Segítségért forduljon az eszköz gyártójához." + "Az eszközön beállított dátum helytelen. Kérjük, ellenőrizze azt." + "Frissítés" + "Belépés" + "Google-bejelentkezés" + + "Egy alkalmazás a Play Szolgáltatások rossz verzióját akarta használni." + "Egy alkalmazás kéri a Google Play Szolgáltatások engedélyezését." + "Egy alkalmazás kéri a Google Play Szolgáltatások telepítését." + "Egy alkalmazás kéri a Google Play Szolgáltatások frissítését." + "Google Play szolgáltatási hiba" + "Igénylő: %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-hy-rAM/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-hy-rAM/strings.xml new file mode 100644 index 0000000000..d89be9bf64 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-hy-rAM/strings.xml @@ -0,0 +1,31 @@ + + + "Տեղադրեք Google Play ծառայությունները" + "Այս հավելվածը չի գործարկվի առանց Google Play ծառայությունների, որոնք բացակայում են ձեր հեռախոսում:" + "Այս հավելվածը չի գործարկվի առանց Google Play ծառայությունների, որոնք բացակայում են ձեր գրասալիկում:" + "Տեղադրել Google Play ծառայությունները" + "Միացնել Google Play ծառայությունները" + "Այս ծրագիրը չի աշխատի, եթե դուք չմիացնեք Google Play ծառայությունները:" + "Միացնել Google Play ծառայությունները" + "Նորացրեք Google Play ծառայությունները" + "Այս ծրագիրը չի գործարկվի, եթե դուք չնորացնեք Google Play ծառայությունները:" + "Ցանցի սխալ կա" + "Պահանջվում է տվյալների կապ` Google Play ծառայություններին միանալու համար:" + "Հաշիվն անվավեր է" + "Նշված հաշիվը գոյություն չունի այս սարքում: Ընտրեք այլ հաշիվ:" + "Անհայտ խնդիր՝ Google Play ծառայություններում:" + "Google Play ծառայություններ" + "Google Play ծառայությունները, որոնց ապավինում են ձեր ծրագրերից որոշները, չեն աջակցվում ձեր սարքի կողմից: Խնդրում ենք կապվել արտադրողի հետ օգնության համար:" + "Սարքի ամսաթիվը կարծես սխալ է: Ստուգեք սարքի ամսաթիվը:" + "Նորացնել" + "Մուտք գործել" + "Մուտք գործեք Google-ով" + + "Հավելվածը փորձել է կիրառել Google Play ծառայությունների վատ տարբերակը:" + "Հավելվածը պահանջում է միացնել Google Play ծառայությունները:" + "Հավելվածը պահանջում է տեղադրել Google Play ծառայությունները:" + "Հավելվածը պահանջում է թարմացնել Google Play ծառայությունները:" + "Google Play ծառայությունների սխալ" + "%1$s-ի հարցմամբ" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-in/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-in/strings.xml new file mode 100644 index 0000000000..526b84a816 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-in/strings.xml @@ -0,0 +1,31 @@ + + + "Dapatkan layanan Google Play" + "Aplikasi ini tidak akan berjalan tanpa layanan Google Play, yang tidak ada di ponsel Anda." + "Aplikasi ini tidak akan berjalan tanpa layanan Google Play, yang tidak ada di tablet Anda." + "Dapatkan layanan Google Play" + "Aktifkan layanan Google Play" + "Aplikasi ini tidak akan bekerja sampai Anda mengaktifkan layanan Google Play." + "Aktifkan layanan Google Play" + "Perbarui layanan Google Play" + "Aplikasi ini tidak akan berjalan sampai Anda memperbarui layanan Google Play." + "Kesalahan Jaringan" + "Sambungan data diperlukan untuk tersambung ke layanan Google Play." + "Akun Tidak Valid" + "Akun yang ditentukan tidak ada di perangkat ini. Pilih akun lain." + "Masalah tidak diketahui pada layanan Google Play." + "Layanan Google Play" + "Layanan Google Play, yang diandalkan oleh beberapa aplikasi Anda, tidak didukung oleh perangkat Anda. Hubungi pabrikan untuk mendapatkan bantuan." + "Tampaknya tanggal di perangkat salah. Periksa tanggal di perangkat." + "Perbarui" + "Masuk" + "Masuk dengan Google" + + "Aplikasi mencoba menggunakan versi Layanan Google Play yang rusak." + "Aplikasi membutuhkan Layanan Google Play untuk dapat diaktifkan." + "Aplikasi membutuhkan pemasangan Layanan Google Play." + "Aplikasi membutuhkan pembaruan untuk Layanan Google Play." + "Kesalahan layanan Google Play" + "Diminta oleh %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-it/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-it/strings.xml new file mode 100644 index 0000000000..f3c9f1fa5c --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-it/strings.xml @@ -0,0 +1,31 @@ + + + "Installa Google Play Services" + "L\'app non funzionerà senza Google Play Services, non presente sul tuo telefono." + "L\'app non funzionerà senza Google Play Services, non presente sul tuo tablet." + "Installa Google Play Services" + "Attiva Google Play Services" + "L\'app non funzionerà se non attivi Google Play Services." + "Attiva Google Play Services" + "Aggiorna Google Play Services" + "L\'app non funzionerà se non aggiorni Google Play Services." + "Errore di rete" + "È necessaria una connessione dati per connettersi a Google Play Services." + "Account non valido" + "L\'account specificato non esiste su questo dispositivo. Scegli un altro account." + "Problema sconosciuto con Google Play Services." + "Google Play Services" + "La piattaforma Google Play Services, su cui sono basate alcune delle tue applicazioni, non è supportata dal dispositivo in uso. Per assistenza, contatta il produttore." + "La data sul dispositivo sembra sbagliata. Controllala." + "Aggiorna" + "Accedi" + "Accedi con Google" + + "Un\'app ha tentato di usare una versione non valida di Play Services." + "Un\'applicazione richiede l\'attivazione di Google Play Services." + "Un\'applicazione richiede l\'installazione di Google Play Services." + "Un\'applicazione richiede un aggiornamento di Google Play Services." + "Errore Google Play Services" + "Richiesta da %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-iw/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-iw/strings.xml new file mode 100644 index 0000000000..76869a9f38 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-iw/strings.xml @@ -0,0 +1,31 @@ + + + "קבל את שירותי Google Play" + "אפליקציה זו לא תפעל ללא שירותי Google Play, החסרים בטלפון שלך." + "אפליקציה זו לא תפעל ללא שירותי Google Play, החסרים בטאבלט שלך." + "קבל את שירותי Google Play" + "הפעלת שירותי Google Play" + "אפליקציה זו לא תעבוד אם לא תפעיל את שירותי Google Play." + "הפעל את שירותי Google Play" + "עדכון שירותי Google Play" + "אפליקציה זו לא תפעל אם לא תעדכן את שירותי Google Play." + "שגיאת רשת." + "דרוש חיבור נתונים כדי להתחבר לשירותי Google Play." + "חשבון לא חוקי" + "החשבון שצוין לא קיים במכשיר זה. בחר חשבון אחר." + "בעיה לא ידועה בשירותי Google Play." + "שירותי Google Play" + "שירותי Google Play, שחלק מהאפליקציות שלך מתבססות עליהם, אינם נתמכים על ידי המכשיר שברשותך. צור קשר עם היצרן לקבלת סיוע." + "נראה שהתאריך במכשיר שגוי. בדוק את התאריך במכשיר." + "עדכן" + "היכנס" + "היכנס באמצעות Google" + + "יש אפליקציה שניסתה להשתמש בגרסה שגויה של שירותי Google Play." + "יש אפליקציה המחייבת הפעלה של שירותי Google Play." + "יש אפליקציה המחייבת התקנה של שירותי Google Play." + "יש אפליקציה המחייבת עדכון של שירותי Google Play." + "שגיאה בשירותי Google Play" + "התבקשה על ידי %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-ja/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-ja/strings.xml new file mode 100644 index 0000000000..0d8b606230 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-ja/strings.xml @@ -0,0 +1,31 @@ + + + "Play開発者サービスの入手" + "このアプリの実行にはGoogle Play開発者サービスが必要ですが、お使いの携帯端末にはインストールされていません。" + "このアプリの実行にはGoogle Play開発者サービスが必要ですが、お使いのタブレットにはインストールされていません。" + "Play開発者サービスの入手" + "Play開発者サービスの有効化" + "このアプリの実行には、Google Play開発者サービスの有効化が必要です。" + "Play開発者サービスの有効化" + "Play開発者サービスの更新" + "このアプリの実行には、Google Play開発者サービスの更新が必要です。" + "ネットワークエラー" + "Google Play開発者サービスに接続するには、データ接続が必要です。" + "無効なアカウント" + "指定したアカウントはこの端末上に存在しません。別のアカウントを選択してください。" + "Google Play開発者サービスで原因不明の問題が発生しました。" + "Google Play開発者サービス" + "一部のアプリが使用しているGoogle Play開発者サービスは、お使いの端末ではサポートされていません。詳しくは、端末メーカーまでお問い合わせください。" + "端末上の日付が正しくないようです。端末上の日付をご確認ください。" + "更新" + "ログイン" + "Googleでログイン" + + "アプリはGoogle Play開発者サービスの不適切なバージョンを使用しようとしました。" + "アプリではGoogle Play開発者サービスを有効にする必要があります。" + "アプリではGoogle Play開発者サービスをインストールする必要があります。" + "アプリではGoogle Play開発者サービスをアップデートする必要があります。" + "Google Play開発者サービスのエラー" + "%1$sによるリクエスト" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-ka-rGE/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-ka-rGE/strings.xml new file mode 100644 index 0000000000..8a2c74aa98 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-ka-rGE/strings.xml @@ -0,0 +1,31 @@ + + + "Google Play სერვისების მიღება" + "ეს აპი ვერ გაეშვება Google Play სერვისების გარეშე, რაც თქვენს ტელეფონზე ვერ იძებნება." + "ეს აპი ვერ გაეშვება Google Play სერვისების გარეშე, რაც თქვენს ტელეფონზე ვერ იძებნება." + "Google Play სერვისების მიღება" + "Google Play სერვისების გააქტიურება" + "ეს აპი არ იმუშავებს, თუ არ გაააქტიურებთ Google Play სერვისებს." + "Google Play სერვისების გააქტიურება" + "Google Play სერვისების განახლება" + "ეს აპი ვერ გაეშვება, თუ Google Play სერვისებს არ განაახლებთ." + "ქსელის შეცდომა" + "Google Play Services-თან დასაკავშირებლად მონაცემთა გადაცემა აუცილებელია." + "ანგარიში არასწორია" + "მითითებული ანგარიში ამ მოწყობილობაზე არ არსებობს. გთხოვთ, აირჩიოთ სხვა ანგარიში." + "Google Play სერვისებთან დაკავშირებით უცნობი შეფერხება წარმოიშვა." + "Google Play სერვისები" + "Google Play სერვისები, რაც თქვენს ზოგიერთ აპს ჭირდება, თქვენს მოწყობილობაზე მხარდაჭერილი არ არის. გთხოვთ, დაუკავშირდეთ მწარმოებელს დახმარებისათვის." + "როგორც ჩანს, მოწყობილობის თარიღი არასწორია. გთხოვთ, შეამოწმოთ მოწყობილობის თარიღი." + "განახლება" + "შესვლა" + "Google-ით შესვლა" + + "აპლიკაცია შეეცადა გამოეყენებინა Google Play სერვისების არასწორი ვერსია." + "აპლიკაცია საჭიროებს გააქტიურებულ Google Play Services." + "აპლიკაცია საჭიროებს Google Play Services-ის ინსტალაციას." + "აპლიკაცია საჭიროებს Google Play Services-ის განახლებას." + "Google Play სერვისების შეცდომა" + "მომთხოვნი: %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-km-rKH/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-km-rKH/strings.xml new file mode 100644 index 0000000000..afebf30875 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-km-rKH/strings.xml @@ -0,0 +1,31 @@ + + + "ទទួល​សេវាកម្ម​កម្សាន្ត Google" + "កម្មវិធី​នេះ​នឹង​មិន​ដំណើរការ​​ទេ​បើ​គ្មាន​​សេវាកម្ម​កម្សាន្ត​ Google ដែល​ទូរស័ព្ទ​របស់​​អ្នក​មិន​មាន។" + "​​កម្មវិធី​នេះ​នឹង​មិន​ដំណើរការ​​ទេ​បើ​គ្មាន​​សេវាកម្ម​កម្សាន្ត​ Google ដែល​​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក​មិន​មាន។" + "ទទួល​សេវាកម្ម​កម្សាន្ត Google" + "បើក​សេវាកម្ម​កម្សាន្ត Google" + "កម្ម​វិធី​នេះ​នឹង​មិន​ដំណើរការ​ទេ​ លុះត្រាតែ​អ្នក​បើក​សេវាកម្ម​​កម្សាន្ត​ Google ។" + "បើក​សេវាកម្ម​កម្សាន្ត Google" + "ធ្វើ​បច្ចុប្បន្នភាព​សេវាកម្ម​កម្សាន្ត Google" + "កម្មវិធី​នេះ​នឹង​មិន​ដំណើរការ​ទេ​ លុះត្រាតែ​អ្នក​ធ្វើ​បច្ចុប្បន្នភាព​សេវាកម្ម​កម្សាន្ត Google ។" + "កំហុស​​បណ្ដាញ" + "បាន​ទាមទារ​ការ​តភ្ជាប់​ទិន្នន័យ ដើម្បី​ភ្ជាប់​សេវាកម្ម​ឃ្លាំង​កម្មវិធី។" + "គណនី​មិន​ត្រឹមត្រូវ" + "គណនី​ដែល​បាន​បញ្ជាក់​មិន​មាន​នៅ​លើ​ឧបករណ៍​នេះ​ទេ។ សូម​ជ្រើស​គណនី​ផ្សេង​។" + "មិន​ស្គាល់​បញ្ហា​ជាមួយ​សេវាកម្ម​កម្សាន្ត Google ។" + "សេវាកម្ម​កម្សាន្ត​ Google" + "សេវាកម្ម​កម្សាន្ត Google អាស្រ័យ​លើ​កម្មវិធី​របស់​អ្នក មិន​ត្រូវ​បាន​គាំទ្រ​ដោយ​ឧបករណ៍​របស់​អ្នក។ សូម​ទាក់ទង​ក្រុមហ៊ុន​ផលិត​សម្រាប់​ជំនួយ។" + "កាលបរិច្ឆេទ​លើ​ឧបករណ៍​បង្ហាញ​ថា​មិន​ត្រឹមត្រូវ។ សូម​ពិនិត្យ​កាលបរិច្ឆេទ​លើ​ឧបករណ៍។" + "ធ្វើ​បច្ចុប្បន្នភាព" + "ចូល" + "ចូល​ដោយ​ប្រើ​ Google" + + "កម្មវិធី​​​ព្យាយាម​ប្រើ​កំណែ​មិនល្អ​របស់​សេវា​កម្ម​ឃ្លាំ​កម្មវិធី។" + "កម្មវិធី​ទាមទារ​​បើក​សេវាកម្ម​ឃ្លាំង​កម្មវិធី។" + "កម្មវិធី​ទាមទារ​ការ​ដំឡើង​សេវាកម្ម​ឃ្លាំង​កម្មវិធី។" + "កម្មវិធី​ទាមទារ​​ធ្វើ​បច្ចុប្បន្នភាព​សេវាកម្ម​ឃ្លាំង​កម្មវិធី។" + "កំហុស​សេវា​កម្ម​កម្សាន្ត Google" + "បាន​ស្នើ​ដោយ %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-ko/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-ko/strings.xml new file mode 100644 index 0000000000..e37f1fd02a --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-ko/strings.xml @@ -0,0 +1,31 @@ + + + "Google Play 서비스 설치" + "휴대전화에 Google Play 서비스가 설치되어 있어야 이 앱이 실행됩니다." + "태블릿에 Google Play 서비스가 설치되어 있어야 이 앱이 실행됩니다." + "Google Play 서비스 설치" + "Google Play 서비스 사용" + "Google Play 서비스를 사용하도록 설정해야 이 앱이 작동합니다." + "Google Play 서비스 사용" + "Google Play 서비스 업데이트" + "Google Play 서비스를 업데이트해야만 이 앱이 실행됩니다." + "네트워크 오류" + "Google Play 서비스에 연결하려면 데이터 연결이 필요합니다." + "올바르지 않은 계정" + "지정한 계정이 이 기기에 존재하지 않습니다. 다른 계정을 선택하세요." + "Google Play 서비스에 알 수 없는 문제가 발생했습니다." + "Google Play 서비스" + "일부 사용자 애플리케이션에 필요한 Google Play 서비스가 사용자 기기에서 지원되지 않습니다. 기기 제조업체에 문의하시기 바랍니다." + "기기의 날짜가 잘못된 것 같습니다. 기기의 날짜를 확인해 주세요." + "업데이트" + "로그인" + "Google 계정으로 로그인" + + "애플리케이션에서 잘못된 버전의 Google Play 서비스를 사용하려고 했습니다." + "Google Play 서비스를 사용하도록 설정해야 하는 애플리케이션입니다." + "Google Play 서비스를 설치해야 하는 애플리케이션입니다." + "Google Play 서비스를 업데이트해야 하는 애플리케이션입니다." + "Google Play 서비스 오류" + "%1$s에서 요청" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-lo-rLA/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-lo-rLA/strings.xml new file mode 100644 index 0000000000..32bcb0b92b --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-lo-rLA/strings.xml @@ -0,0 +1,31 @@ + + + "ຕິດຕັ້ງບໍລິການ Google Play" + "ແອັບຯນີ້ຈະບໍ່ສາມາດເຮັດວຽກໄດ້ໂດຍທີ່ບໍ່ມີບໍລິການ Google Play ເຊິ່ງຂາດຫາຍໄປໃນໂທລະສັບຂອງທ່ານ." + "ແອັບຯນີ້ຈະບໍ່ສາມາດເຮັດວຽກໄດ້ໂດຍທີ່ບໍ່ມີບໍລິການ Google Play ເຊິ່ງຂາດຫາຍໄປໃນແທັບເລັດຂອງທ່ານ." + "ຕິດຕັ້ງບໍລິການ Google Play" + "ເປີດໃຊ້ບໍລິການ Google Play" + "ແອັບຯນີ້ຈະບໍ່ສາມາດເຮັດວຽກໄດ້ຈົນກວ່າທ່ານຈະເປີດໃຊ້ບໍລິການ Google Play" + "ເປີດໃຊ້ບໍລິການ Google Play" + "ອັບເດດບໍລິການ Google Play" + "ແອັບຯນີ້ຈະບໍ່ສາມາດເຮັດວຽກໄດ້ຈົນກວ່າທ່ານຈະອັບເດດບໍລິການ Google Play." + "ເຄືອຂ່າຍຜິດພາດ" + "ຕ້ອງໃຊ້ການເຊື່ອມຕໍ່ອິນເຕີເນັດເພື່ອໃຊ້ Google Play Services." + "ບັນຊີບໍ່ຖືກຕ້ອງ" + "ບັນຊີທີ່ເລືອກບໍ່ມີໃນອຸປະກອນນີ້. ກະລຸນາເລືອກບັນຊີອື່ນ." + "ມີປັນຫາທີ່ບໍ່ຄາດຄິດໃນບໍລິການ Google Play." + "ບໍລິການ Google Play" + "ບໍລິການ Google Play ທີ່ບາງແອັບພລິເຄຊັນຂອງທ່ານຕ້ອງອາໄສນັ້ນ ບໍ່ຖືກຮອງຮັບໃນອຸປະກອນຂອງທ່ານ. ກະລຸນາຕິດຕໍ່ຜູ້ຜະລິດສຳລັບການແນະນຳ." + "ວັນທີຂອງອຸປະກອນບໍ່ຖືກຕ້ອງ. ກະລຸນາກວດສອບວັນທີຂອງອຸປະກອນຂອງທ່ານ." + "ອັບເດດ" + "ເຂົ້າສູ່ລະບົບ" + "ເຂົ້າສູ່ລະບົບດ້ວຍ Google" + + "ແອັບພລິເຄຊັນໄດ້ພະຍາຍາມໃຊ້ Google Play Services ເວີຊັນທີ່ບໍ່ສາມາດໃຊ້ໄດ້." + "ແອັບພລິເຄຊັນຕ້ອງການເປີດນຳໃຊ້ Google Play Services." + "ແອັບພລິເຄຊັນຕ້ອງການໃຫ້ຕິດຕັ້ງ Google Play Services." + "ແອັບພລິເຄຊັນຕ້ອງການອັບເດດ Google Play Services." + "ບໍລິການ Google Play ຜິດພາດ" + "ຮ້ອງຂໍໂດຍ %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-lt/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-lt/strings.xml new file mode 100644 index 0000000000..73de5fa9aa --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-lt/strings.xml @@ -0,0 +1,31 @@ + + + "Gauti „Google Play“ paslaugų" + "Ši programa neveiks be „Google Play“ paslaugų, kurios neįdiegtos telefone." + "Ši programa neveiks be „Google Play“ paslaugų, kurios neįdiegtos planšetiniame kompiuteryje." + "Gauti „Google Play“ paslaugų" + "Įgalinti „Google Play“ paslaugas" + "Ši programa neveiks, jei neįgalinsite „Google Play“ paslaugų." + "Įgal. „Google Play“ paslaugas" + "Atnaujinti „Google Play“ paslaugas" + "Ši programa neveiks, jei neatnaujinsite „Google Play“ paslaugų." + "Tinklo klaida" + "Norint prisijungti prie „Google Play“ paslaugų reikia duomenų ryšio." + "Netinkama paskyra" + "Nurodytos paskyros šiame įrenginyje nėra. Pasirinkite kitą paskyrą." + "Nežinoma „Google Play“ paslaugų problema." + "„Google Play“ paslaugos" + "Jūsų įrenginys nepalaiko „Google Play“ paslaugų, kuriomis remiasi kai kurios programos. Jei reikia pagalbos, susisiekite su gamintoju." + "Įrenginyje nurodyta data neteisinga. Patikrinkite įrenginyje nurodytą datą." + "Atnaujinti" + "Prisij." + "Prisij. naud. „Google“" + + "Programa bandė naudotis netinkama „Google Play“ paslaugų versija." + "Norint naudoti programą būtina įgalinti „Google Play“ paslaugas." + "Norint naudoti programą būtina įdiegti „Google Play“ paslaugas." + "Norint naudoti programą būtina atnaujinti „Google Play“ paslaugas." + "„Google Play“ paslaugų klaida" + "Užklausą pateikė „%1$s“" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-lv/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-lv/strings.xml new file mode 100644 index 0000000000..9e4b6ee6bd --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-lv/strings.xml @@ -0,0 +1,31 @@ + + + "Google Play pakalpojumu iegūšana" + "Lai šī lietotne darbotos, tālrunī ir jāinstalē Google Play pakalpojumi." + "Lai šī lietotne darbotos, planšetdatorā ir jāinstalē Google Play pakalpojumi." + "Iegūt Google Play pakalpojumus" + "Google Play pakalpojumu iespējošana" + "Lai šī lietotne darbotos, iespējojiet Google Play pakalpojumus." + "Iespējot Google Play pakalpojumus" + "Google Play pakalpojumu atjaunināšana" + "Lai šī lietotne darbotos, atjauniniet Google Play pakalpojumus." + "Tīkla kļūda" + "Lai izveidotu savienojumu ar Google Play pakalpojumiem, ir nepieciešams datu savienojums." + "Nederīgs konts" + "Norādītais konts šajā ierīcē nepastāv. Lūdzu, izvēlieties citu kontu." + "Nezināma problēma ar Google Play pakalpojumiem." + "Google Play pakalpojumi" + "Jūsu ierīce neatbalsta Google Play pakalpojumus, kuri nepieciešami dažu jūsu lietojumprogrammu darbībai. Lūdzu, sazinieties ar ražotāju, lai saņemtu palīdzību." + "Šķiet, ka ierīcē ir iestatīts nepareizs datums. Lūdzu, pārbaudiet ierīces datumu." + "Atjaunināt" + "Pierakst." + "Pierakstīties Google" + + "Lietojumpr. mēģināja izmantot nederīgu Google Play pakalp. versiju." + "Lai lietojumprogramma darbotos, ir jāiespējo Google Play pakalpojumi." + "Lai lietojumprogramma darbotos, ir jāinstalē Google Play pakalpojumi." + "Lai lietojumprogramma darbotos, jāatjaunina Google Play pakalpojumi." + "Google Play pakalpojumu kļūda" + "Pieprasījums no lietotnes %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-mn-rMN/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-mn-rMN/strings.xml new file mode 100644 index 0000000000..1743256a11 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-mn-rMN/strings.xml @@ -0,0 +1,31 @@ + + + "Google Play үйлчилгээ авах" + "Таны утсанд байхгүй байгаа Google Play үйлчилгээг идэвхжүүлж байж энэ апп-г ажиллуулах боломжтой." + "Таны таблетэд байхгүй Google Play үйлчилгээг идэвхжүүлж байж энэ апп-г ажиллуулах боломжтой." + "Google Play үйлчилгээ авах" + "Google Play үйлчилгээг идэвхжүүлэх" + "Та Google Play үйлчилгээг идэвхжүүлж байж энэ апп-г ажиллуулах боломжтой." + "Google Play үйлчилгээг идэвхжүүлэх" + "Google Play үйлчилгээг шинэчлэх" + "Та Google Play үйлчилгээг шинэчлэхгүй бол энэ апп ажиллах боломжгүй." + "Сүлжээний алдаа" + "Google Play үйлчилгээнд холбогдохын тулд дата холболт шаардлагатай." + "Буруу акаунт" + "Заасан акаунт энэ төхөөрөмж дээр байхгүй байна. Өөр акаунт сонгоно уу." + "Google Play үйлчилгээтэй холбоотой тодорхойгүй алдаа." + "Google Play үйлчилгээ" + "Таны зарим аппликешнүүдийн хамаардаг Google Play үйлчилгээ таны төхөөрөмжид дэмжигдэхгүй байна. Тусламж авахын тулд үйлдвэрлэгчтэй холбоо барина уу." + "Төхөөрөмжийн огноо буруу байгаа бололтой. Төхөөрөмжийн огноог шалгана уу." + "Шинэчлэх" + "Нэвтрэх" + "Google-р нэвтрэх:" + + "Аппликешн Google Play Үйлчилгээний муу хувилбарыг ашиглахыг оролдлоо." + "Аппликешн Google Play Үйлчилгээг идэвхжүүлсэн байхыг шаардана." + "Аппликешн Google Play Үйлчилгээг суулгахыг шаардана." + "Аппликешн Google Play Үйлчилгээг шинэчлэхийг шаардана." + "Google Play үйлчилгээний алдаа" + "Хүсэлт гаргасан %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-ms-rMY/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-ms-rMY/strings.xml new file mode 100644 index 0000000000..8e8a4b9b8a --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-ms-rMY/strings.xml @@ -0,0 +1,31 @@ + + + "Dapatkan perkhidmatan Google Play" + "Apl ini tidak akan berfungsi tanpa perkhidmatan Google Play dan apl ini tiada pada telefon anda." + "Apl ini tidak akan berfungsi tanpa perkhidmatan Google Play dan apl ini tiada pada tablet anda." + "Dapatkan perkhidmatan Google Play" + "Dayakan perkhidmatan Google Play" + "Apl ini tidak akan berfungsi kecuali anda mendayakan perkhidmatan Google Play." + "Dayakan perkhidmatan Google Play" + "Kemas kini perkhidmatan Google Play" + "Apl ini tidak akan berfungsi kecuali anda mengemas kini perkhidmatan Google Play." + "Ralat Rangkaian" + "Sambungan data diperlukan untuk menyambung ke perkhidmatan Google Play." + "Akaun Tidak Sah" + "Akaun yang dinyatakan tidak wujud pada peranti ini. Sila pilih akaun yang lain." + "Isu tidak diketahui dengan perkhidmatan Google Play." + "Perkhidmatan Google Play" + "Peranti anda tidak menyokong perkhidmatan Google Play, sedangkan sesetengah aplikasi anda memerlukannya. Sila hubungi pengilang untuk bantuan." + "Tarikh pada peranti kelihatan tidak betul. Sila semak tarikh pada peranti." + "Kemas kini" + "Log masuk" + "Log masuk dengan Google" + + "Aplikasi cuba menggunakan versi Perkhidmatan Google Play yang rosak." + "Perkhidmatan Google Play perlu didayakan untuk menggunakan aplikasi." + "Perkhidmatan Google Play perlu dipasang untuk mengguankan aplikasi." + "Perkhidmatan Google Play perlu dikemas kini untuk menggunakan aplikasi." + "Ralat perkhidmatan Google Play" + "Diminta oleh %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-ms/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-ms/strings.xml new file mode 100644 index 0000000000..8e8a4b9b8a --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-ms/strings.xml @@ -0,0 +1,31 @@ + + + "Dapatkan perkhidmatan Google Play" + "Apl ini tidak akan berfungsi tanpa perkhidmatan Google Play dan apl ini tiada pada telefon anda." + "Apl ini tidak akan berfungsi tanpa perkhidmatan Google Play dan apl ini tiada pada tablet anda." + "Dapatkan perkhidmatan Google Play" + "Dayakan perkhidmatan Google Play" + "Apl ini tidak akan berfungsi kecuali anda mendayakan perkhidmatan Google Play." + "Dayakan perkhidmatan Google Play" + "Kemas kini perkhidmatan Google Play" + "Apl ini tidak akan berfungsi kecuali anda mengemas kini perkhidmatan Google Play." + "Ralat Rangkaian" + "Sambungan data diperlukan untuk menyambung ke perkhidmatan Google Play." + "Akaun Tidak Sah" + "Akaun yang dinyatakan tidak wujud pada peranti ini. Sila pilih akaun yang lain." + "Isu tidak diketahui dengan perkhidmatan Google Play." + "Perkhidmatan Google Play" + "Peranti anda tidak menyokong perkhidmatan Google Play, sedangkan sesetengah aplikasi anda memerlukannya. Sila hubungi pengilang untuk bantuan." + "Tarikh pada peranti kelihatan tidak betul. Sila semak tarikh pada peranti." + "Kemas kini" + "Log masuk" + "Log masuk dengan Google" + + "Aplikasi cuba menggunakan versi Perkhidmatan Google Play yang rosak." + "Perkhidmatan Google Play perlu didayakan untuk menggunakan aplikasi." + "Perkhidmatan Google Play perlu dipasang untuk mengguankan aplikasi." + "Perkhidmatan Google Play perlu dikemas kini untuk menggunakan aplikasi." + "Ralat perkhidmatan Google Play" + "Diminta oleh %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-nb/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-nb/strings.xml new file mode 100644 index 0000000000..1e16bbb6d2 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-nb/strings.xml @@ -0,0 +1,31 @@ + + + "Installer Google Play Tjenester" + "Denne appen kan ikke kjøres uten Google Play Tjenester, som ikke er installert på telefonen din." + "Denne appen kan ikke kjøres uten Google Play Tjenester, som ikke er installert på nettbrettet ditt." + "Installer Google Play Tjenester" + "Aktiver Google Play Tjenester" + "Denne appen fungerer ikke med mindre du aktiverer Google Play Tjenester." + "Aktiver Google Play Tjenester" + "Oppdater Google Play Tjenester" + "Denne appen kan ikke kjøres før du oppdaterer Google Play Tjenester." + "Nettverksfeil" + "Du må ha datatilkobling for å koble deg til Google Play-tjenester." + "Ugyldig konto" + "Den angitte kontoen finnes ikke på enheten. Velg en annen konto." + "Det oppsto et ukjent problem med Google Play Tjenester." + "Google Play-tjenester" + "Google Play Tjenester, som noen av appene er avhengige av, støttes ikke av enheten. Ta kontakt med produsenten for å få hjelp." + "Datoen på enheten ser ut til å være feil. Sjekk datoen på enheten." + "Oppdater" + "Logg på" + "Logg inn med Google" + + "En app prøvde å bruke en skadet versjon av Google Play Tjenester." + "En app krever Google Play Tjenester for å aktiveres." + "En app krever at Google Play Tjenester installeres." + "En app krever at Google Play Tjenester oppdateres." + "Google Play Tjenester-feil" + "Forespurt av %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-nl/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-nl/strings.xml new file mode 100644 index 0000000000..f38db5fcdb --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-nl/strings.xml @@ -0,0 +1,31 @@ + + + "Google Play-services ophalen" + "Deze app kan niet worden uitgevoerd zonder Google Play-services die ontbreken op uw telefoon." + "Deze app kan niet worden uitgevoerd zonder Google Play-services die ontbreken op uw tablet." + "Google Play-services ophalen" + "Google Play-services inschakelen" + "Deze app werkt niet, tenzij u Google Play-services inschakelt." + "Google Play-services inschak." + "Google Play-services bijwerken" + "Deze app kan niet worden uitgevoerd, tenzij u Google Play-services bijwerkt." + "Netwerkfout" + "Er is een gegevensverbinding nodig om verbinding te kunnen maken met Google Play-services." + "Ongeldig account" + "Het gespecificeerde account bestaat niet op dit apparaat. Kies een ander account." + "Onbekend probleem met Google Play-services." + "Google Play-services" + "Google Play-services, dat vereist is voor een aantal van uw applicaties, wordt niet ondersteund door uw apparaat. Neem contact op met de fabrikant voor ondersteuning." + "De datum op het apparaat lijkt onjuist. Controleer de datum op het apparaat." + "Bijwerken" + "Inloggen" + "Inloggen met Google" + + "Onjuiste versie van Google Play-services wordt gebruikt." + "Google Play-services moet zijn ingeschakeld voor een applicatie." + "Google Play-services moet zijn geïnstalleerd voor een applicatie." + "Google Play-services moet worden geüpdatet voor een applicatie." + "Fout met Google Play-services" + "Aangevraagd door %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-pl/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-pl/strings.xml new file mode 100644 index 0000000000..5eba15ff3a --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-pl/strings.xml @@ -0,0 +1,31 @@ + + + "Pobierz Usługi Google Play" + "Ta aplikacja nie będzie działać bez Usług Google Play, których nie masz na telefonie." + "Ta aplikacja nie będzie działać bez Usług Google Play, których nie masz na tablecie." + "Pobierz Usługi Google Play" + "Włącz Usługi Google Play" + "Ta aplikacja nie będzie działać, jeśli nie włączysz Usług Google Play." + "Włącz Usługi Google Play" + "Aktualizuj Usługi Google Play" + "Ta aplikacja nie będzie działać, jeśli nie zaktualizujesz Usług Google Play." + "Błąd sieci" + "Korzystanie z usług Google Play wymaga połączenia z internetem." + "Nieprawidłowe konto" + "Podanego konta nie ma na tym urządzeniu. Wybierz inne konto." + "Nieznany problem z Usługami Google Play." + "Usługi Google Play" + "Usługi Google Play, od których zależy działanie niektórych aplikacji, nie są obsługiwane na Twoim urządzeniu. Skontaktuj się z producentem, by uzyskać pomoc." + "Data ustawiona na urządzeniu wydaje się nieprawidłowa. Sprawdź datę ustawioną na urządzeniu." + "Aktualizuj" + "Zaloguj się" + "Zaloguj się przez Google" + + "Aplikacja próbowała skorzystać z nieprawidłowej wersji Usług Google Play." + "Aplikacja wymaga włączenia Usług Google Play." + "Aplikacja wymaga zainstalowania Usług Google Play." + "Aplikacja wymaga aktualizacji Usług Google Play." + "Błąd usług Google Play" + "Żądanie z aplikacji %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-pt-rBR/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000000..6db462d709 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-pt-rBR/strings.xml @@ -0,0 +1,31 @@ + + + "Instale o Google Play Services" + "Este aplicativo não funciona sem o Google Play Services, que não está instalado em seu telefone." + "Este aplicativo não funciona sem o Google Play Services, que não está instalado em seu tablet." + "Instalar o Google Play Services" + "Ative o Google Play Services" + "Este aplicativo só funciona com o Google Play Services ativado." + "Ativar o Google Play Services" + "Atualize o Google Play Services" + "Este aplicativo só funciona com uma versão atualizada do Google Play Services." + "Erro na rede" + "É necessária uma conexão de dados para conectar ao Google Play Services." + "Conta inválida" + "A conta especificada não existe no dispositivo. Escolha outra conta." + "Problema desconhecido com o Google Play Services." + "Play Services" + "O Google Play Services, necessário para alguns dos aplicativos, não é compatível com seu dispositivo. Entre em contato com o fabricante para obter assistência." + "A data no dispositivo parece incorreta. Verifique a data no dispositivo." + "Atualizar" + "Login" + "Fazer login com o Google" + + "Um aplicativo tentou usar uma versão errada do Google Play Services." + "Um aplicativo requer a ativação do Google Play Services." + "Um aplicativo requer a instalação do Google Play Services." + "Um aplicativo requer a atualização do Google Play Services." + "Ocorreu um erro no Google Play Services" + "Solicitado por %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-pt-rPT/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-pt-rPT/strings.xml new file mode 100644 index 0000000000..0ceafcb95f --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-pt-rPT/strings.xml @@ -0,0 +1,31 @@ + + + "Obter serviços do Google Play" + "Esta aplicação não será executada sem os serviços do Google Play, que estão em falta no seu telemóvel." + "Esta aplicação não será executada sem os serviços do Google Play, que estão em falta no seu tablet." + "Obter serviços do Google Play" + "Ativar serviços do Google Play" + "Esta aplicação não funcionará enquanto não ativar os serviços do Google Play." + "Ativar serviços do Google Play" + "Atualizar serviços do Google Play" + "Esta aplicação não será executada enquanto não atualizar os serviços do Google Play." + "Erro de Rede" + "É necessária uma ligação de dados para se ligar aos Serviços do Google Play." + "Conta Inválida" + "A conta especificada não existe neste dispositivo. Escolha uma conta diferente." + "Problema desconhecido nos serviços do Google Play." + "Serviços do Google Play" + "Os serviços do Google Play, dos quais dependem algumas das suas aplicações, não são suportados pelo seu dispositivo. Contacte o fabricante para obter assistência." + "A data no dispositivo parece estar incorreta. Verifique a data no dispositivo." + "Atualizar" + "Inic. ses." + "Inic. sessão com o Google" + + "Aplicação tentou utiliz. versão incorreta dos Serviços do Google Play." + "Uma aplicação necessita da ativação dos Serviços do Google Play." + "Uma aplicação necessita da instalação dos Serviços do Google Play." + "Uma aplicação necessita da atualização dos Serviços do Google Play." + "Erro dos serviços do Google Play" + "Solicitado por %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-pt/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-pt/strings.xml new file mode 100644 index 0000000000..6db462d709 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-pt/strings.xml @@ -0,0 +1,31 @@ + + + "Instale o Google Play Services" + "Este aplicativo não funciona sem o Google Play Services, que não está instalado em seu telefone." + "Este aplicativo não funciona sem o Google Play Services, que não está instalado em seu tablet." + "Instalar o Google Play Services" + "Ative o Google Play Services" + "Este aplicativo só funciona com o Google Play Services ativado." + "Ativar o Google Play Services" + "Atualize o Google Play Services" + "Este aplicativo só funciona com uma versão atualizada do Google Play Services." + "Erro na rede" + "É necessária uma conexão de dados para conectar ao Google Play Services." + "Conta inválida" + "A conta especificada não existe no dispositivo. Escolha outra conta." + "Problema desconhecido com o Google Play Services." + "Play Services" + "O Google Play Services, necessário para alguns dos aplicativos, não é compatível com seu dispositivo. Entre em contato com o fabricante para obter assistência." + "A data no dispositivo parece incorreta. Verifique a data no dispositivo." + "Atualizar" + "Login" + "Fazer login com o Google" + + "Um aplicativo tentou usar uma versão errada do Google Play Services." + "Um aplicativo requer a ativação do Google Play Services." + "Um aplicativo requer a instalação do Google Play Services." + "Um aplicativo requer a atualização do Google Play Services." + "Ocorreu um erro no Google Play Services" + "Solicitado por %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-ro/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-ro/strings.xml new file mode 100644 index 0000000000..eb428964ec --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-ro/strings.xml @@ -0,0 +1,31 @@ + + + "Descărcaţi Servicii Google Play" + "Această aplicaţie nu poate rula fără Servicii Google Play, care lipsesc de pe telefon." + "Această aplicaţie nu poate rula fără Servicii Google Play, care lipsesc de pe tabletă." + "Obţineţi Servicii Google Play" + "Activaţi Servicii Google Play" + "Această aplicaţie nu va funcţiona decât dacă activaţi Servicii Google Play." + "Activaţi Servicii Google Play" + "Actualizaţi Servicii Google Play" + "Această aplicaţie nu poate rula decât dacă actualizaţi Servicii Google Play." + "Eroare de reţea" + "Este necesară o conexiune de date pentru a vă conecta la serviciile Google Play." + "Cont nevalid" + "Contul menționat nu există pe acest dispozitiv. Alegeți alt cont." + "Problemă necunoscută privind Servicii Google Play." + "Servicii Google Play" + "Gadgetul nu acceptă serviciile Google Play, pe care se bazează unele dintre aplicații. Pentru asistență, contactați producătorul gadgetului." + "Data de pe dispozitiv pare să fie incorectă. Verificați data de pe dispozitiv." + "Actualizaţi" + "Conectați" + "Conectați-vă cu Google" + + "Aplicația a încercat să utilizeze o vers. Servicii Google Play greșită" + "O aplicație necesită activarea Serviciilor Google Play." + "O aplicație necesită instalarea Serviciilor Google Play." + "O aplicație necesită o actualizare pentru Servicii Google Play." + "Eroare Servicii Google Play" + "Solicitată de %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-ru/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-ru/strings.xml new file mode 100644 index 0000000000..c784aae95c --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-ru/strings.xml @@ -0,0 +1,31 @@ + + + "Установите Сервисы Google Play" + "Для работы этого приложения требуется установить Сервисы Google Play." + "Для работы этого приложения требуется установить Сервисы Google Play." + "Установить" + "Включите Сервисы Google Play" + "Для работы этого приложения требуется включить Сервисы Google Play." + "Включить" + "Обновите Сервисы Google Play" + "Для работы этого приложения требуется обновить Сервисы Google Play." + "Ошибка сети" + "Для работы с Google Play требуется подключение к сети." + "Недействительный аккаунт" + "Этого аккаунта нет на устройстве. Выберите другой." + "Неизвестная ошибка с Сервисами Google Play." + "Сервисы Google Play" + "Сервисы Google Play, необходимые для работы некоторых приложений, не поддерживаются на вашем устройстве. Обратитесь к производителю." + "Проверьте правильность даты, указанной на устройстве." + "Обновить" + "Войти" + "Войти в аккаунт Google" + + "Версия сервисов Google Play неисправна" + "Для работы приложения требуется включить сервисы Google Play" + "Для работы приложения требуется установить сервисы Google Play" + "Для работы приложения требуется обновить сервисы Google Play" + "Ошибка сервисов Google Play" + "Запрос от приложения \"%1$s\"" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-sk/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-sk/strings.xml new file mode 100644 index 0000000000..125d87f6da --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-sk/strings.xml @@ -0,0 +1,31 @@ + + + "Inštalovať služby Google Play" + "Na spustenie tejto aplikácie sa vyžadujú služby Google Play, ktoré v telefóne nemáte." + "Na spustenie tejto aplikácie sa vyžadujú služby Google Play, ktoré v tablete nemáte." + "Inštalovať služby Google Play" + "Povoliť služby Google Play" + "Táto aplikácia bude fungovať až po povolení služieb Google Play." + "Povoliť služby Google Play" + "Aktualizovať služby Google Play" + "Túto aplikáciu bude možné spustiť až po aktualizácii služieb Google Play." + "Chyba siete" + "Pripojenie k službám Google Play si vyžaduje dátové pripojenie." + "Neplatný účet" + "Zadaný účet v tomto zariadení neexistuje. Vyberte iný účet." + "Neznámy problém so službami Google Play." + "Služby Google Play" + "Niektoré vaše aplikácie vyžadujú služby Google Play, ktoré vo vašom zariadení nie sú podporované. Ak potrebujete pomoc, kontaktujte výrobcu." + "Dátum nastavený v zariadení sa zdá byť nesprávny. Skontrolujte ho." + "Aktualizovať" + "Prihlásiť sa" + "Prihlásiť sa do účtu Google" + + "Aplikácia sa pokúsila použiť nesprávnu verziu služieb Google Play." + "Aplikácia vyžaduje povolenie služieb Google Play." + "Aplikácia vyžaduje inštaláciu služieb Google Play." + "Aplikácia vyžaduje aktualizáciu služieb Google Play." + "Chyba služieb Google Play" + "Vyžiadané aplikáciou %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-sl/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-sl/strings.xml new file mode 100644 index 0000000000..df5821f94c --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-sl/strings.xml @@ -0,0 +1,31 @@ + + + "Namestite storitve Google Play" + "Ta aplikacija ne deluje brez storitev Google Play, ki jih ni v telefonu." + "Ta aplikacija ne deluje brez storitev Google Play, ki jih ni v tabličnem računalniku." + "Namestite storitve Google Play" + "Omogočite storitve Google Play" + "Aplikacija ne bo delovala, če ne omogočite storitev Google Play." + "Omogočite storitve Google Play" + "Posodobite storitve Google Play" + "Ta aplikacija ne deluje, če ne posodobite storitev Google Play." + "Omrežna napaka" + "Za povezavo s storitvami Google Play potrebujete internetno povezavo." + "Neveljaven račun" + "V tej napravi ne obstaja navedeni račun. Izberite drugega." + "Neznana težava s storitvami Google Play." + "Storitve Google Play" + "Vaša naprava na podpira storitev Google Play, ki jih potrebujejo nekatere od vaših aplikacij. Za pomoč se obrnite na izdelovalca." + "Videti je, da je datum v napravi napačen. Preverite ga." + "Posodobi" + "Prijava" + "Prijavite se v Google" + + "Aplikacija je poskusila uporabiti napačno različico Storitev Google Play." + "Za delovanje aplikacije morate omogočiti Storitve Google Play." + "Za delovanje aplikacije morate namestiti Storitve Google Play." + "Za delovanje aplikacije morate posodobiti Storitve Google Play." + "Napaka storitev Google Play" + "Zahtevala aplikacija %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-sr/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-sr/strings.xml new file mode 100644 index 0000000000..ad0b549547 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-sr/strings.xml @@ -0,0 +1,31 @@ + + + "Преузимање Google Play услуга" + "Ова апликација не може да се покрене без Google Play услуга, које недостају на телефону." + "Ова апликација не може да се покрене без Google Play услуга, које недостају на таблету." + "Преузми Google Play услуге" + "Омогућавање Google Play услуга" + "Ова апликација неће функционисати ако не омогућите Google Play услуге." + "Омогући Google Play услуге" + "Ажурирање Google Play услуга" + "Ова апликација не може да се покрене ако не ажурирате Google Play услуге." + "Грешка на мрежи" + "За повезивање са Google Play услугама потребна је веза за пренос података." + "Неважећи налог" + "Наведени налог не постоји на овом уређају. Одаберите други налог." + "Непознат проблем са Google Play услугама." + "Google Play услуге" + "Google Play услуге, које су потребне за функционисање неких од апликација, нису подржане на уређају. Контактирајте произвођача да бисте добили помоћ." + "Изгледа да су подаци на уређају нетачни. Проверите датум на уређају." + "Ажурирај" + "Пријави ме" + "Пријави ме преко Google-а" + + "Апликација је покушала да користи лошу верзију Google Play услуга." + "Апликација захтева да Google Play услуге буду омогућене." + "Апликација захтева инсталирање Google Play услуга." + "Апликација захтева ажурирање Google Play услуга." + "Грешка Google Play услуга" + "Захтева %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-sv/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-sv/strings.xml new file mode 100644 index 0000000000..6a10395f4b --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-sv/strings.xml @@ -0,0 +1,31 @@ + + + "Hämta Google Play Tjänster" + "Den här appen kan inte köras utan Google Play Tjänster, som saknas på mobilen." + "Den här appen kan inte köras utan Google Play Tjänster, som saknas på surfplattan." + "Hämta Google Play Tjänster" + "Aktivera Google Play Tjänster" + "Du måste aktivera Google Play Tjänster för att den här appen ska fungera." + "Aktivera Google Play Tjänster" + "Uppdatera Google Play Tjänster" + "Du måste uppdatera Google Play Tjänster innan du kan köra den här appen." + "Nätverksfel" + "En dataanslutning krävs för att ansluta till Google Plays tjänster." + "Ogiltigt konto" + "Det angivna kontot finns inte på den här enheten. Välj ett annat konto." + "Okänt problem med Google Play Tjänster" + "Google Play-tjänster" + "Några av dina appar använder Google Play-tjänster som inte stöds av din enhet. Kontakta tillverkaren om du vill ha hjälp." + "Datumet på enheten verkar inte vara rätt. Kontrollera datumet på enheten." + "Uppdatera" + "Logga in" + "Logga in med Google" + + "En olämplig version av Google Play Tjänster anropades av en app." + "Google Play Tjänster måste aktiveras för en att app ska fungera." + "Google Play Tjänster måste installeras för att en app ska fungera." + "Google Play Tjänster måste uppdateras för en app ska fungera." + "Fel på Google Play Tjänster" + "Begärdes av %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-sw/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-sw/strings.xml new file mode 100644 index 0000000000..37bd92ac68 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-sw/strings.xml @@ -0,0 +1,31 @@ + + + "Pata huduma za Google Play" + "Programu hii haiwezi kuendeshwa bila huduma za Google Play, ambazo hazipo kwenye simu yako." + "Programu hii haiwezi kuendeshwa bila huduma za Google Play, ambazo hazipo kwenye kompyuta yako ndogo." + "Pata huduma za Google Play" + "Wezesha huduma za Google Play" + "Programu hii haitafanya kazi mpaka utakapowezesha huduma za Google Play." + "Wezesha huduma za Google Play" + "Sasisha huduma za Google Play" + "Programu hii haiwezi kuendeshwa mpaka utakaposasisha huduma za Google Play." + "Hitilafu ya Mtandao" + "Muunganisho wa data unahitajika ili kuunganisha kwenye huduma za Google Play." + "Akaunti Batili" + "Akaunti iliyobainishwa haipo kwenye kifaa hiki. Tafadhali chagua akaunti tofauti." + "Suala lisilojulikana na huduma za Google Play." + "Huduma za Google Play" + "Huduma za Google Play, ambazo baadhi ya programu zako zinategemea, si linganifu na kifaa chako. Tafadhali wasiliana na mtengenezaji kwa usaidizi." + "Inaeonekana tarehe ya kifaa sio sahihi. Tafadhali angalia tarehe ya kifaa." + "Sasisha" + "Ingia" + "Ingia ukitumia Google" + + "Programu ilijaribu kutumia toleo baya la Huduma za Google Play." + "Programu inahitaji Huduma za Google Play ili kuwashwa." + "Programu inahitaji usakinishaji wa Huduma za Google Play." + "Programu inahitaji sasisho la Huduma za Google Play." + "Hitilafu kwenye Huduma za Google Play" + "Imeombwa na %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-th/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-th/strings.xml new file mode 100644 index 0000000000..6f098fe801 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-th/strings.xml @@ -0,0 +1,31 @@ + + + "รับบริการ Google Play" + "แอปพลิเคชันนี้จะไม่ทำงานหากไม่มีบริการ Google Play ซึ่งไม่มีในโทรศัพท์ของคุณ" + "แอปพลิเคชันนี้จะไม่ทำงานหากไม่มีบริการ Google Play ซึ่งไม่มีในแท็บเล็ตของคุณ" + "รับบริการ Google Play" + "เปิดใช้งานบริการ Google Play" + "แอปพลิเคชันนี้จะไม่ทำงานจนกว่าคุณจะเปิดใช้งานบริการ Google Play" + "เปิดใช้งานบริการ Google Play" + "อัปเดตบริการ Google Play" + "แอปพลิเคชันนี้จะไม่ทำงานจนกว่าคุณจะอัปเดตบริการ Google Play" + "ข้อผิดพลาดของเครือข่าย" + "ต้องมีการเขื่อมต่อข้อมูลเพื่อเชื่อมต่อกับบริการ Google Play" + "บัญชีไม่ถูกต้อง" + "บัญชีที่ระบุไม่มีอยู่บนอุปกรณ์นี้ โปรดเลือกบัญชีอื่น" + "ปัญหาที่ไม่รู้จักของบริการ Google Play" + "บริการ Google Play" + "บริการ Google Play ซึ่งใช้งานในบางแอปพลิเคชัน ไม่ได้รับการสนับสนุนโดยอุปกรณ์ของคุณ โปรดติดต่อผู้ผลิตเพื่อขอรับความช่วยเหลือ" + "วันที่บนอุปกรณ์ไม่ถูกต้อง โปรดตรวจสอบวันที่บนอุปกรณ์" + "อัปเดต" + "ลงชื่อใช้" + "ลงชื่อเข้าใช้ด้วย Google" + + "แอปพลิเคชันหนึ่งพยายามใช้เวอร์ชันที่ไม่เหมาะสมของบริการ Google Play" + "แอปพลิเคชันหนึ่งจำเป็นต้องมีบริการ Google Play เพื่อเปิดใช้งาน" + "แอปพลิเคชันหนึ่งจำเป็นต้องมีการติดตั้งบริการ Google Play" + "แอปพลิเคชันหนึ่งจำเป็นต้องมีการอัปเดตสำหรับบริการ Google Play" + "ข้อผิดพลาดของบริการ Google Play" + "ขอโดย %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-tl/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-tl/strings.xml new file mode 100644 index 0000000000..337f73c0cd --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-tl/strings.xml @@ -0,0 +1,31 @@ + + + "Kumuha ng mga serbisyo ng Google Play" + "Hindi tatakbo ang app na ito nang wala ang mga serbisyo ng Google Play, na wala sa iyong telepono." + "Hindi gagana ang app na ito nang wala ang mga serbisyo ng Google Play, na wala sa iyong tablet." + "Kumuha ng Google Play services" + "Paganahin ang Google Play services" + "Hindi gagana ang app na ito maliban kung papaganahin mo ang mga serbisyo ng Google Play." + "Enable Google Play services" + "I-update ang mga serbisyo ng Google Play" + "Hindi gagana ang app na ito maliban kung i-a-update mo ang mga serbisyo ng Google Play." + "May Error sa Network" + "Kailangan ng koneksyon ng data upang makakonekta sa mga serbisyo ng Google Play." + "Di-wasto ang Account" + "Hindi umiiral ang tinukoy na account sa device na ito. Mangyaring pumili ng ibang account." + "May hindi alam na isyu sa mga serbisyo ng Google Play." + "Mga serbisyo ng Google Play" + "Ang mga serbisyo ng Google Play, kung saan nakadepende ang ilan sa iyong mga application, ay hindi sinusuportahan ng iyong device. Mangyaring makipag-ugnay sa manufacturer para sa tulong." + "Mukhang hindi tama ang petsa sa device. Pakisuri ang petsa sa device." + "I-update" + "Sign in" + "Mag-sign in sa Google" + + "May app na sumubok ng maling bersyon ng Mga Serbisyo ng Google Play." + "Kailangan ng application na na-enable ang Mga Serbisyo ng Google Play." + "Kailangan ng application na ma-install ang Serbisyo ng Google Play." + "Kailangan ng application na i-update ang Mga Serbisyo ng Google Play." + "Error sa mga serbisyo ng Google Play" + "Hiniling ng %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-tr/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-tr/strings.xml new file mode 100644 index 0000000000..17e61e5fcb --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-tr/strings.xml @@ -0,0 +1,31 @@ + + + "Google Play hizmetlerini edinin" + "Google Play Hizmetleri telefonunuzda yok ve bu uygulama Google Play Hizmetleri olmadan çalışmaz." + "Google Play Hizmetleri tabletinizde yok ve bu uygulama Google Play Hizmetleri olmadan çalışmaz." + "Google Play hizmetlerini edin" + "Google Play hizmetlerini etkinleştir" + "Bu uygulama, Google Play Hizmetleri etkinleştirilmeden çalışmaz" + "Google Play hizmetlerini etkinleştir" + "Google Play hizmetlerini güncelle" + "Bu uygulama Google Play Hizmetleri güncellenmeden çalışmaz." + "Ağ Hatası" + "Google Play hizmetlerine bağlanmak için bir veri bağlantısı gerekiyor." + "Geçersiz Hesap" + "Belirtilen hesap bu cihazda mevcut değil. Lütfen farklı bir hesap seçin." + "Google Play hizmetleriyle ilgili bilinmeyen sorun." + "Google Play hizmetleri" + "Cihazınız, uygulamalarınızdan bazıları için gerekli olan Google Play hizmetlerini desteklemiyor. Lütfen yardım için üreticiyle iletişim kurun." + "Cihazdaki tarih doğru görünmüyor. Lütfen cihazda ayarlı tarihi kontrol edin." + "Güncelle" + "Oturum aç" + "Google\'da oturum aç" + + "Bir uygulama, Google Play Hizmetleri\'nin bozuk bir sürümünü kullanmayı denedi." + "Bir uygulama, Google Play Hizmetleri\'nin etkin olmasını gerektiriyor." + "Bir uygulama, Google Play Hizmetleri\'nin yüklenmesini gerektiriyor." + "Bir uygulama, Google Play Hizmetleri için bir güncelleme gerektiriyor." + "Google Play hizmetleri hatası" + "İstekte bulunan: %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-uk/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-uk/strings.xml new file mode 100644 index 0000000000..d657aea68d --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-uk/strings.xml @@ -0,0 +1,31 @@ + + + "Установити Google Play Послуги" + "Ця програма не запуститься без Google Play Послуг, яких немає у вашому телефоні." + "Ця програма не запуститься без Google Play Послуг, яких немає на вашому планшетному ПК." + "Установити Google Play Послуги" + "Увімкнути Google Play Послуги" + "Ця програма не працюватиме, поки ви не ввімкнете Google Play Послуги." + "Увімкнути Google Play Послуги" + "Оновити Google Play Послуги" + "Ця програма не запуститься, поки ви не оновите Google Play Послуги." + "Помилка мережі" + "Для під’єднання до сервісів Google Play потрібне з’єднання з мережею." + "Недійсний обліковий запис" + "Указаний обліковий запис не існує на цьому пристрої. Виберіть інший обліковий запис." + "Google Play Послуги – невідома проблема." + "Сервіси Google Play" + "Ваш пристрій не підтримує Сервіси Google Play, від яких залежить робота деяких програм. Зверніться по допомогу до виробника." + "Схоже, на пристрої вказано неправильну дату. Перевірте її." + "Оновити" + "Увійти" + "Увійти в обл.запис Google" + + "Програма спробувала застосувати хибну версію Сервісів Google Play." + "Щоб програма працювала, потрібно ввімкнути Сервіси Google Play." + "Щоб програма працювала, потрібно встановити Сервіси Google Play." + "Щоб програма працювала, потрібно оновити Сервіси Google Play." + "Помилка Сервісів Google Play" + "Запит від програми %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-vi/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-vi/strings.xml new file mode 100644 index 0000000000..a0434a08ac --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-vi/strings.xml @@ -0,0 +1,31 @@ + + + "Cài đặt dịch vụ của Google Play" + "Ứng dụng này sẽ không chạy nếu không có dịch vụ của Google Play. Điện thoại của bạn bị thiếu dịch vụ này." + "Ứng dụng này sẽ không chạy nếu không có dịch vụ của Google Play. Máy tính bảng của bạn bị thiếu dịch vụ này." + "Cài đặt dịch vụ của Google Play" + "Bật dịch vụ của Google Play" + "Ứng dụng này sẽ không hoạt động trừ khi bạn bật dịch vụ của Google Play." + "Bật dịch vụ của Google Play" + "Cập nhật dịch vụ của Google Play" + "Ứng dụng này sẽ không chạy trừ khi bạn cập nhật dịch vụ của Google Play." + "Lỗi mạng" + "Cần có kết nối dữ liệu để kết nối với các dịch vụ của Google Play." + "Tài khoản không hợp lệ" + "Tài khoản đã chỉ định không tồn tại trên thiết bị này. Vui lòng chọn một tài khoản khác." + "Sự cố không xác định với dịch vụ của Google Play." + "Dịch vụ của Google Play" + "Các dịch vụ của Google Play mà một số ứng dụng của bạn dựa vào không được thiết bị của bạn hỗ trợ. Vui lòng liên hệ với nhà sản xuất để được hỗ trợ." + "Ngày trên thiết bị có vẻ không chính xác. Vui lòng kiểm tra ngày trên thiết bị." + "Cập nhật" + "Đăng nhập" + "Đăng nhập bằng Google" + + "Ứng dụng đã cố sử dụng phiên bản không đúng của Dịch vụ của Google Play." + "Ứng dụng yêu cầu Dịch vụ của Google Play phải được bật." + "Ứng dụng yêu cầu cài đặt Dịch vụ của Google Play." + "Ứng dụng yêu cầu cập nhật dành cho Dịch vụ Google Play." + "Lỗi dịch vụ của Google Play" + "Được yêu cầu bởi %1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-zh-rCN/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000..4339e3eb01 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-zh-rCN/strings.xml @@ -0,0 +1,31 @@ + + + "获取 Google Play 服务" + "您的手机中没有 Google Play 服务,您必须先安装该服务才能运行此应用。" + "您的平板电脑中没有 Google Play 服务,您必须先安装该服务才能运行此应用。" + "获取 Google Play 服务" + "启用 Google Play 服务" + "您必须先启用 Google Play 服务才能运行此应用。" + "启用 Google Play 服务" + "更新 Google Play 服务" + "您必须先更新 Google Play 服务才能运行此应用。" + "网络错误" + "您必须有数据网络连接才能接入 Google Play 服务。" + "无效帐户" + "此设备上不存在指定的帐户,请选择其他帐户。" + "Google Play 服务出现未知问题。" + "Google Play 服务" + "您的设备不支持部分应用所依赖的 Google Play 服务。请与设备制造商联系,以寻求帮助。" + "设备上的日期似乎不正确,请在设备上检查日期。" + "更新" + "登录" + "使用 Google 帐户登录" + + "某个应用尝试使用的 Google Play 服务版本有误。" + "某个应用要求启用 Google Play 服务。" + "某个应用要求安装 Google Play 服务。" + "某个应用要求更新 Google Play 服务。" + "Google Play 服务出错" + "由“%1$s”发出" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-zh-rHK/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-zh-rHK/strings.xml new file mode 100644 index 0000000000..abe6cf1457 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-zh-rHK/strings.xml @@ -0,0 +1,31 @@ + + + "取得 Google Play 服務" + "您的手機未安裝 Google Play 服務,安裝後才能執行這個應用程式。" + "您的平板電腦未安裝 Google Play 服務,安裝後才能執行這個應用程式。" + "取得 Google Play 服務" + "啟用 Google Play 服務" + "您必須啟用 Google Play 服務,才能執行這個應用程式。" + "啟用 Google Play 服務" + "更新 Google Play 服務" + "您必須更新 Google Play 服務,才能執行這個應用程式。" + "網絡錯誤" + "要連接 Google Play 服務,必需數據連線。" + "無效的帳戶" + "這個裝置上沒有您指定的帳戶,請選擇其他帳戶。" + "Google Play 服務出現不明問題。" + "Google Play 服務" + "您的裝置不支援部分應用程式所需的 Google Play 服務。如需協助,請與您的裝置製造商聯絡。" + "裝置上的日期看來不正確,請檢查裝置上的日期。" + "更新" + "登入" + "登入 Google" + + "應用程式嘗試使用錯誤版本的「Google Play 服務」。" + "必須啟用「Google Play 服務」,才能使用應用程式。" + "必須安裝「Google Play 服務」,才能使用應用程式。" + "必須更新「Google Play 服務」,才能使用應用程式。" + "Google Play 服務錯誤" + "「%1$s」提出要求" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-zh-rTW/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000000..a66018ab52 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-zh-rTW/strings.xml @@ -0,0 +1,31 @@ + + + "取得 Google Play 服務" + "您的手機並未安裝 Google Play 服務,所以無法執行這個應用程式。" + "您的平板電腦並未安裝 Google Play 服務,所以無法執行這個應用程式。" + "取得 Google Play 服務" + "啟用 Google Play 服務" + "您必須啟用 Google Play 服務,這個應用程式才能運作。" + "啟用 Google Play 服務" + "更新 Google Play 服務" + "您必須更新 Google Play 服務,才能執行這個應用程式。" + "網路錯誤" + "需要數據連線才能連上 Google Play 服務。" + "無效的帳戶" + "這個裝置上沒有您所指定的帳戶,請選擇其他帳戶。" + "Google Play 服務發生不明問題。" + "Google Play 服務" + "您的裝置不支援部分應用程式所需的 Google Play 服務。如需協助,請與您的裝置製造商聯絡。" + "裝置上的日期似乎不正確,請檢查裝置上的日期。" + "更新" + "登入" + "使用 Google 帳戶登入" + + "應用程式嘗試使用的 Google Play 服務版本有誤。" + "應用程式需要啟用 Google Play 服務。" + "應用程式需要安裝 Google Play 服務。" + "應用程式需要更新 Google Play 服務。" + "Google Play 服務錯誤" + "提出要求的應用程式:%1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values-zu/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values-zu/strings.xml new file mode 100644 index 0000000000..572d9a52c4 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values-zu/strings.xml @@ -0,0 +1,31 @@ + + + "Thola amasevisi e-Google Play" + "Lolu hlelo lokusebenza ngeke lusebenze ngaphandle kwamasevisi e-Google Play, angekho efonini yakho." + "Lolu hlelo lokusebenza ngeke lusebenze ngaphandle kwamasevisi e-Google Play, angekho kuthebulethi yakho." + "Thola amasevisi e-Google Play" + "Nika amandla amasevisi e-Google Play" + "Lolu hlelo lokusebenza ngeke lusebenze ngaphandle nje kokuthi unike amandla amasevisi e-Google Play." + "Nika amandla amasevisi e-Google Play" + "Buyekeza amasevisi e-Google Play" + "Lolu hlelo lokusebenza ngeke lusebenze ngaphandle nje kokuthi ubuyekeze amasevisi e-Google Play." + "Iphutha lenethiwekhi" + "Kudingeka ukuxhumeka kwedatha ukuze kuxhunyekwe kumasevisi we-Google Play." + "I-Akhawunti engavumelekile" + "I-Akhawunti ecacisiwe ayikho kule divayisi. Sicela ukhethe i-akhawunti ehlukile." + "Indaba engaziwa yamasevisi we-Google Play" + "Amasevisi we-Google Play" + "Amasevisi we-Google Play, okungukuthi ezinye izinhlelo zakho zithembele kuwo, awasekelwe yidivayisi yakho. Sicela uxhumane nomkhiqizi ukuze uthole usizo." + "Idethi kudivayisi ibonakala ingalungile. Sicela uhlole idethi kudivayisi." + "Isibuyekezo" + "Ngena ngemvume" + "Ngena ngemvume nge-Google" + + "Uhlelo lokusebenza luzame ukusebenzisa inguqulo embi yamasevisi we-Google Play." + "Uhlelo lokusebenza ludinga amasevisi we-Google Play ukuze anikwe amandla." + "Uhlelo lokusebenza ludinga ukufakwa kwamasevisi we-Google Play." + "Uhlelo lokusebenza ludinga isibuyekezo samasevisi we-Google Play." + "Iphutha lamasevisi we-Google Play" + "Kucelwe yi-%1$s" + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values/ads_attrs.xml b/pkg/android/phoenix64/libs/googleplay/res/values/ads_attrs.xml new file mode 100644 index 0000000000..519a84272b --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values/ads_attrs.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values/colors.xml b/pkg/android/phoenix64/libs/googleplay/res/values/colors.xml new file mode 100644 index 0000000000..6b2740a509 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values/colors.xml @@ -0,0 +1,14 @@ + + + + @android:color/white + @android:color/white + #FFAAAAAA + @android:color/white + #FF737373 + @android:color/white + #FFAAAAAA + #FF737373 + #FFDD4B39 + #d2d2d2 + \ No newline at end of file diff --git a/pkg/android/phoenix64/libs/googleplay/res/values/maps_attrs.xml b/pkg/android/phoenix64/libs/googleplay/res/values/maps_attrs.xml new file mode 100644 index 0000000000..aaf65c529e --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values/maps_attrs.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values/strings.xml b/pkg/android/phoenix64/libs/googleplay/res/values/strings.xml new file mode 100644 index 0000000000..24bd58b11d --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values/strings.xml @@ -0,0 +1,111 @@ + + + + + Get Google Play services + + + This app won\'t run without Google Play services, which are missing from your phone. + + + This app won\'t run without Google Play services, which are missing from your tablet. + + + Get Google Play services + + + Enable Google Play services + + + This app won\'t work unless you enable Google Play services. + + + Enable Google Play services + + + Update Google Play services + + + This app won\'t run unless you update Google Play services. + + + Network Error + + + A data connection is required to connect to Google Play services. + + + Invalid Account + + + The specified account does not exist on this device. Please choose a different account. + + + Unknown issue with Google Play services. + + + Google Play services + + + Google Play services, which some of your applications rely on, is not supported by your device. Please contact the manufacturer for assistance. + + + The date on the device appears to be incorrect. Please check the date on the device. + + + Update + + + Sign in + + + Sign in with Google + + + + + + An application attempted to use a bad version of Google Play Services. + + + + An application requires Google Play Services to be enabled. + + + + An application requires installation of Google Play Services. + + + + An application requires an update for Google Play Services. + + + + Google Play services error + + + Requested by %1$s + + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/res/values/version.xml b/pkg/android/phoenix64/libs/googleplay/res/values/version.xml new file mode 100644 index 0000000000..890d9119aa --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/res/values/version.xml @@ -0,0 +1,4 @@ + + + 4030500 + diff --git a/pkg/android/phoenix64/libs/googleplay/src/android/.readme b/pkg/android/phoenix64/libs/googleplay/src/android/.readme new file mode 100644 index 0000000000..4bcebad80c --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/src/android/.readme @@ -0,0 +1,2 @@ +This hidden file is there to ensure there is an src folder. +Once we support binary library this will go away. \ No newline at end of file diff --git a/pkg/android/phoenix64/msvc-2017-android.NativeActivity.vcxproj b/pkg/android/phoenix64/msvc-2017-android.NativeActivity.vcxproj new file mode 100644 index 0000000000..bc86a3ea31 --- /dev/null +++ b/pkg/android/phoenix64/msvc-2017-android.NativeActivity.vcxproj @@ -0,0 +1,273 @@ + + + + + Debug + ARM + + + Release + ARM + + + Debug + ARM64 + + + Release + ARM64 + + + Debug + x64 + + + Release + x64 + + + Debug + x86 + + + Release + x86 + + + + + CompileAsC + CompileAsC + CompileAsC + CompileAsC + CompileAsC + CompileAsC + CompileAsC + CompileAsC + + + c++11 + c++11 + c++11 + c++11 + c++11 + c++11 + c++11 + c++11 + + + c++11 + c++11 + c++11 + c++11 + c++11 + c++11 + c++11 + c++11 + + + + {e27d73ec-6148-4817-b75c-adaa0c563939} + Android + retroarch-activity + en-US + 14.0 + Android + 3.0 + retroarch-activity.NativeActivity + + + + DynamicLibrary + true + Clang_3_8 + c++_static + android-24 + + + DynamicLibrary + false + Clang_3_8 + c++_static + android-24 + + + DynamicLibrary + true + Clang_3_8 + c++_static + android-24 + + + DynamicLibrary + false + Clang_3_8 + c++_static + android-24 + + + DynamicLibrary + true + Clang_3_8 + c++_static + android-24 + + + DynamicLibrary + false + Clang_3_8 + c++_static + android-24 + + + DynamicLibrary + true + Clang_3_8 + c++_static + android-24 + + + DynamicLibrary + false + Clang_3_8 + c++_static + android-24 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + CompileAsCpp + $(SolutionDir)\..\..\..\libretro-common\include;$(SolutionDir)\..\..\..\deps;$(SolutionDir)\..\..\..\deps\libFLAC\include;$(SolutionDir)\..\..\..\deps\stb;$(SolutionDir)\..\..\..\deps\7zip;$(SolutionDir)\..\..\..\gfx\include;$(SolutionDir)\..\..\..\deps\glslang;$(SolutionDir)\..\..\..\deps\glslang\glslang\Public;$(SolutionDir)\..\..\..\deps\glslang\glslang\MachineIndependent;$(SolutionDir)\..\..\..\deps\glslang\glslang\SPIRV;$(SolutionDir)\..\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) + HAVE_OPENGLES2;RARCH_MOBILE;HAVE_GRIFFIN;HAVE_STB_VORBIS;HAVE_LANGEXTRA;ANDROID;HAVE_DYNAMIC;HAVE_OPENGL;HAVE_OVERLAY;HAVE_OPENGLES;HAVE_DYLIB;HAVE_EGL;HAVE_GLSL;HAVE_MENU;HAVE_RGUI;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;INLINE=inline;HAVE_THREADS;__LIBRETRO__;HAVE_RSOUND;HAVE_NETWORKGAMEPAD;HAVE_NETWORKING;RARCH_INTERNAL;HAVE_FILTERS_BUILTIN;HAVE_MATERIALUI;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_LIBRETRODB;HAVE_STB_FONT;HAVE_IMAGEVIEWER;HAVE_UPDATE_ASSETS;HAVE_CC_RESAMPLER;HAVE_MINIUPNPC;HAVE_BUILTINMINIUPNPC;MINIUPNPC_SET_SOCKET_TIMEOUT;MINIUPNPC_GET_SRC_ADDR;HAVE_KEYMAPPER;HAVE_FLAC;HAVE_DR_FLAC;HAVE_DR_MP3;HAVE_CHD;HAVE_RUNAHEAD;ENABLE_HLSL;WANT_IFADDRS;HAVE_7ZIP;HAVE_CHEEVOS;HAVE_SL;FLAC_PACKAGE_VERSION="\"retroarch\"";HAVE_LROUND;FLAC__HAS_OGG=0;DONT_WANT_ARM_OPTIMIZATIONS;__STDC_LIMIT_MACROS;%(PreprocessorDefinitions) + Enabled + + + %(LibraryDependencies);GLESv2;EGL;dl;z;m;OpenSLES + + + + + NotUsing + CompileAsCpp + $(SolutionDir)\..\..\..\libretro-common\include;$(SolutionDir)\..\..\..\deps;$(SolutionDir)\..\..\..\deps\libFLAC\include;$(SolutionDir)\..\..\..\deps\stb;$(SolutionDir)\..\..\..\deps\7zip;$(SolutionDir)\..\..\..\gfx\include;$(SolutionDir)\..\..\..\deps\glslang;$(SolutionDir)\..\..\..\deps\glslang\glslang\Public;$(SolutionDir)\..\..\..\deps\glslang\glslang\MachineIndependent;$(SolutionDir)\..\..\..\deps\glslang\glslang\SPIRV;$(SolutionDir)\..\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) + HAVE_OPENGLES2;RARCH_MOBILE;HAVE_GRIFFIN;HAVE_STB_VORBIS;HAVE_LANGEXTRA;ANDROID;HAVE_DYNAMIC;HAVE_OPENGL;HAVE_OVERLAY;HAVE_OPENGLES;HAVE_DYLIB;HAVE_EGL;HAVE_GLSL;HAVE_MENU;HAVE_RGUI;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;INLINE=inline;HAVE_THREADS;__LIBRETRO__;HAVE_RSOUND;HAVE_NETWORKGAMEPAD;HAVE_NETWORKING;RARCH_INTERNAL;HAVE_FILTERS_BUILTIN;HAVE_MATERIALUI;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_LIBRETRODB;HAVE_STB_FONT;HAVE_IMAGEVIEWER;HAVE_UPDATE_ASSETS;HAVE_CC_RESAMPLER;HAVE_MINIUPNPC;HAVE_BUILTINMINIUPNPC;MINIUPNPC_SET_SOCKET_TIMEOUT;MINIUPNPC_GET_SRC_ADDR;HAVE_KEYMAPPER;HAVE_FLAC;HAVE_DR_FLAC;HAVE_DR_MP3;HAVE_CHD;HAVE_RUNAHEAD;ENABLE_HLSL;WANT_IFADDRS;HAVE_7ZIP;HAVE_CHEEVOS;HAVE_SL;FLAC_PACKAGE_VERSION="\"retroarch\"";HAVE_LROUND;FLAC__HAS_OGG=0;DONT_WANT_ARM_OPTIMIZATIONS;__STDC_LIMIT_MACROS;%(PreprocessorDefinitions) + Enabled + + + %(LibraryDependencies);GLESv2;EGL;dl;z;m;OpenSLES + + + + + NotUsing + CompileAsCpp + $(SolutionDir)\..\..\..\libretro-common\include;$(SolutionDir)\..\..\..\deps;$(SolutionDir)\..\..\..\deps\libFLAC\include;$(SolutionDir)\..\..\..\deps\stb;$(SolutionDir)\..\..\..\deps\7zip;$(SolutionDir)\..\..\..\gfx\include;$(SolutionDir)\..\..\..\deps\glslang;$(SolutionDir)\..\..\..\deps\glslang\glslang\Public;$(SolutionDir)\..\..\..\deps\glslang\glslang\MachineIndependent;$(SolutionDir)\..\..\..\deps\glslang\glslang\SPIRV;$(SolutionDir)\..\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) + HAVE_OPENGLES2;RARCH_MOBILE;HAVE_GRIFFIN;HAVE_STB_VORBIS;HAVE_LANGEXTRA;ANDROID;HAVE_DYNAMIC;HAVE_OPENGL;HAVE_OVERLAY;HAVE_OPENGLES;HAVE_DYLIB;HAVE_EGL;HAVE_GLSL;HAVE_MENU;HAVE_RGUI;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;INLINE=inline;HAVE_THREADS;__LIBRETRO__;HAVE_RSOUND;HAVE_NETWORKGAMEPAD;HAVE_NETWORKING;RARCH_INTERNAL;HAVE_FILTERS_BUILTIN;HAVE_MATERIALUI;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_LIBRETRODB;HAVE_STB_FONT;HAVE_IMAGEVIEWER;HAVE_UPDATE_ASSETS;HAVE_CC_RESAMPLER;HAVE_MINIUPNPC;HAVE_BUILTINMINIUPNPC;MINIUPNPC_SET_SOCKET_TIMEOUT;MINIUPNPC_GET_SRC_ADDR;HAVE_KEYMAPPER;HAVE_FLAC;HAVE_DR_FLAC;HAVE_DR_MP3;HAVE_CHD;HAVE_RUNAHEAD;ENABLE_HLSL;WANT_IFADDRS;HAVE_7ZIP;HAVE_CHEEVOS;HAVE_SL;FLAC_PACKAGE_VERSION="\"retroarch\"";HAVE_LROUND;FLAC__HAS_OGG=0;DONT_WANT_ARM_OPTIMIZATIONS;__STDC_LIMIT_MACROS;%(PreprocessorDefinitions) + Enabled + + + %(LibraryDependencies);GLESv2;EGL;dl;z;m;OpenSLES + + + + + NotUsing + CompileAsCpp + $(SolutionDir)\..\..\..\libretro-common\include;$(SolutionDir)\..\..\..\deps;$(SolutionDir)\..\..\..\deps\libFLAC\include;$(SolutionDir)\..\..\..\deps\stb;$(SolutionDir)\..\..\..\deps\7zip;$(SolutionDir)\..\..\..\gfx\include;$(SolutionDir)\..\..\..\deps\glslang;$(SolutionDir)\..\..\..\deps\glslang\glslang\Public;$(SolutionDir)\..\..\..\deps\glslang\glslang\MachineIndependent;$(SolutionDir)\..\..\..\deps\glslang\glslang\SPIRV;$(SolutionDir)\..\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) + HAVE_OPENGLES2;RARCH_MOBILE;HAVE_GRIFFIN;HAVE_STB_VORBIS;HAVE_LANGEXTRA;ANDROID;HAVE_DYNAMIC;HAVE_OPENGL;HAVE_OVERLAY;HAVE_OPENGLES;HAVE_DYLIB;HAVE_EGL;HAVE_GLSL;HAVE_MENU;HAVE_RGUI;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;INLINE=inline;HAVE_THREADS;__LIBRETRO__;HAVE_RSOUND;HAVE_NETWORKGAMEPAD;HAVE_NETWORKING;RARCH_INTERNAL;HAVE_FILTERS_BUILTIN;HAVE_MATERIALUI;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_LIBRETRODB;HAVE_STB_FONT;HAVE_IMAGEVIEWER;HAVE_UPDATE_ASSETS;HAVE_CC_RESAMPLER;HAVE_MINIUPNPC;HAVE_BUILTINMINIUPNPC;MINIUPNPC_SET_SOCKET_TIMEOUT;MINIUPNPC_GET_SRC_ADDR;HAVE_KEYMAPPER;HAVE_FLAC;HAVE_DR_FLAC;HAVE_DR_MP3;HAVE_CHD;HAVE_RUNAHEAD;ENABLE_HLSL;WANT_IFADDRS;HAVE_7ZIP;HAVE_CHEEVOS;HAVE_SL;FLAC_PACKAGE_VERSION="\"retroarch\"";HAVE_LROUND;FLAC__HAS_OGG=0;DONT_WANT_ARM_OPTIMIZATIONS;__STDC_LIMIT_MACROS;%(PreprocessorDefinitions) + Enabled + + + %(LibraryDependencies);GLESv2;EGL;dl;z;m;OpenSLES + + + + + NotUsing + CompileAsCpp + $(SolutionDir)\..\..\..\libretro-common\include;$(SolutionDir)\..\..\..\deps;$(SolutionDir)\..\..\..\deps\libFLAC\include;$(SolutionDir)\..\..\..\deps\stb;$(SolutionDir)\..\..\..\deps\7zip;$(SolutionDir)\..\..\..\gfx\include;$(SolutionDir)\..\..\..\deps\glslang;$(SolutionDir)\..\..\..\deps\glslang\glslang\Public;$(SolutionDir)\..\..\..\deps\glslang\glslang\MachineIndependent;$(SolutionDir)\..\..\..\deps\glslang\glslang\SPIRV;$(SolutionDir)\..\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) + HAVE_OPENGLES2;RARCH_MOBILE;HAVE_GRIFFIN;HAVE_STB_VORBIS;HAVE_LANGEXTRA;ANDROID;HAVE_DYNAMIC;HAVE_OPENGL;HAVE_OVERLAY;HAVE_OPENGLES;HAVE_DYLIB;HAVE_EGL;HAVE_GLSL;HAVE_MENU;HAVE_RGUI;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;INLINE=inline;HAVE_THREADS;__LIBRETRO__;HAVE_RSOUND;HAVE_NETWORKGAMEPAD;HAVE_NETWORKING;RARCH_INTERNAL;HAVE_FILTERS_BUILTIN;HAVE_MATERIALUI;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_LIBRETRODB;HAVE_STB_FONT;HAVE_IMAGEVIEWER;HAVE_UPDATE_ASSETS;HAVE_CC_RESAMPLER;HAVE_MINIUPNPC;HAVE_BUILTINMINIUPNPC;MINIUPNPC_SET_SOCKET_TIMEOUT;MINIUPNPC_GET_SRC_ADDR;HAVE_KEYMAPPER;HAVE_FLAC;HAVE_DR_FLAC;HAVE_DR_MP3;HAVE_CHD;HAVE_RUNAHEAD;ENABLE_HLSL;WANT_IFADDRS;HAVE_7ZIP;HAVE_CHEEVOS;HAVE_SL;FLAC_PACKAGE_VERSION="\"retroarch\"";HAVE_LROUND;FLAC__HAS_OGG=0;DONT_WANT_ARM_OPTIMIZATIONS;__STDC_LIMIT_MACROS;%(PreprocessorDefinitions) + Enabled + + + %(LibraryDependencies);GLESv2;EGL;dl;z;m;OpenSLES + + + + + NotUsing + CompileAsCpp + $(SolutionDir)\..\..\..\libretro-common\include;$(SolutionDir)\..\..\..\deps;$(SolutionDir)\..\..\..\deps\libFLAC\include;$(SolutionDir)\..\..\..\deps\stb;$(SolutionDir)\..\..\..\deps\7zip;$(SolutionDir)\..\..\..\gfx\include;$(SolutionDir)\..\..\..\deps\glslang;$(SolutionDir)\..\..\..\deps\glslang\glslang\Public;$(SolutionDir)\..\..\..\deps\glslang\glslang\MachineIndependent;$(SolutionDir)\..\..\..\deps\glslang\glslang\SPIRV;$(SolutionDir)\..\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) + HAVE_OPENGLES2;RARCH_MOBILE;HAVE_GRIFFIN;HAVE_STB_VORBIS;HAVE_LANGEXTRA;ANDROID;HAVE_DYNAMIC;HAVE_OPENGL;HAVE_OVERLAY;HAVE_OPENGLES;HAVE_DYLIB;HAVE_EGL;HAVE_GLSL;HAVE_MENU;HAVE_RGUI;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;INLINE=inline;HAVE_THREADS;__LIBRETRO__;HAVE_RSOUND;HAVE_NETWORKGAMEPAD;HAVE_NETWORKING;RARCH_INTERNAL;HAVE_FILTERS_BUILTIN;HAVE_MATERIALUI;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_LIBRETRODB;HAVE_STB_FONT;HAVE_IMAGEVIEWER;HAVE_UPDATE_ASSETS;HAVE_CC_RESAMPLER;HAVE_MINIUPNPC;HAVE_BUILTINMINIUPNPC;MINIUPNPC_SET_SOCKET_TIMEOUT;MINIUPNPC_GET_SRC_ADDR;HAVE_KEYMAPPER;HAVE_FLAC;HAVE_DR_FLAC;HAVE_DR_MP3;HAVE_CHD;HAVE_RUNAHEAD;ENABLE_HLSL;WANT_IFADDRS;HAVE_7ZIP;HAVE_CHEEVOS;HAVE_SL;FLAC_PACKAGE_VERSION="\"retroarch\"";HAVE_LROUND;FLAC__HAS_OGG=0;DONT_WANT_ARM_OPTIMIZATIONS;__STDC_LIMIT_MACROS;%(PreprocessorDefinitions) + Enabled + + + %(LibraryDependencies);GLESv2;EGL;dl;z;m;OpenSLES + + + + + NotUsing + CompileAsCpp + $(SolutionDir)\..\..\..\libretro-common\include;$(SolutionDir)\..\..\..\deps;$(SolutionDir)\..\..\..\deps\libFLAC\include;$(SolutionDir)\..\..\..\deps\stb;$(SolutionDir)\..\..\..\deps\7zip;$(SolutionDir)\..\..\..\gfx\include;$(SolutionDir)\..\..\..\deps\glslang;$(SolutionDir)\..\..\..\deps\glslang\glslang\Public;$(SolutionDir)\..\..\..\deps\glslang\glslang\MachineIndependent;$(SolutionDir)\..\..\..\deps\glslang\glslang\SPIRV;$(SolutionDir)\..\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) + HAVE_OPENGLES2;RARCH_MOBILE;HAVE_GRIFFIN;HAVE_STB_VORBIS;HAVE_LANGEXTRA;ANDROID;HAVE_DYNAMIC;HAVE_OPENGL;HAVE_OVERLAY;HAVE_OPENGLES;HAVE_DYLIB;HAVE_EGL;HAVE_GLSL;HAVE_MENU;HAVE_RGUI;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;INLINE=inline;HAVE_THREADS;__LIBRETRO__;HAVE_RSOUND;HAVE_NETWORKGAMEPAD;HAVE_NETWORKING;RARCH_INTERNAL;HAVE_FILTERS_BUILTIN;HAVE_MATERIALUI;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_LIBRETRODB;HAVE_STB_FONT;HAVE_IMAGEVIEWER;HAVE_UPDATE_ASSETS;HAVE_CC_RESAMPLER;HAVE_MINIUPNPC;HAVE_BUILTINMINIUPNPC;MINIUPNPC_SET_SOCKET_TIMEOUT;MINIUPNPC_GET_SRC_ADDR;HAVE_KEYMAPPER;HAVE_FLAC;HAVE_DR_FLAC;HAVE_DR_MP3;HAVE_CHD;HAVE_RUNAHEAD;ENABLE_HLSL;WANT_IFADDRS;HAVE_7ZIP;HAVE_CHEEVOS;HAVE_SL;FLAC_PACKAGE_VERSION="\"retroarch\"";HAVE_LROUND;FLAC__HAS_OGG=0;DONT_WANT_ARM_OPTIMIZATIONS;__STDC_LIMIT_MACROS;%(PreprocessorDefinitions) + Enabled + + + %(LibraryDependencies);GLESv2;EGL;dl;z;m;OpenSLES + + + + + NotUsing + CompileAsCpp + $(SolutionDir)\..\..\..\libretro-common\include;$(SolutionDir)\..\..\..\deps;$(SolutionDir)\..\..\..\deps\libFLAC\include;$(SolutionDir)\..\..\..\deps\stb;$(SolutionDir)\..\..\..\deps\7zip;$(SolutionDir)\..\..\..\gfx\include;$(SolutionDir)\..\..\..\deps\glslang;$(SolutionDir)\..\..\..\deps\glslang\glslang\Public;$(SolutionDir)\..\..\..\deps\glslang\glslang\MachineIndependent;$(SolutionDir)\..\..\..\deps\glslang\glslang\SPIRV;$(SolutionDir)\..\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) + HAVE_OPENGLES2;RARCH_MOBILE;HAVE_GRIFFIN;HAVE_STB_VORBIS;HAVE_LANGEXTRA;ANDROID;HAVE_DYNAMIC;HAVE_OPENGL;HAVE_OVERLAY;HAVE_OPENGLES;HAVE_DYLIB;HAVE_EGL;HAVE_GLSL;HAVE_MENU;HAVE_RGUI;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;INLINE=inline;HAVE_THREADS;__LIBRETRO__;HAVE_RSOUND;HAVE_NETWORKGAMEPAD;HAVE_NETWORKING;RARCH_INTERNAL;HAVE_FILTERS_BUILTIN;HAVE_MATERIALUI;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_LIBRETRODB;HAVE_STB_FONT;HAVE_IMAGEVIEWER;HAVE_UPDATE_ASSETS;HAVE_CC_RESAMPLER;HAVE_MINIUPNPC;HAVE_BUILTINMINIUPNPC;MINIUPNPC_SET_SOCKET_TIMEOUT;MINIUPNPC_GET_SRC_ADDR;HAVE_KEYMAPPER;HAVE_FLAC;HAVE_DR_FLAC;HAVE_DR_MP3;HAVE_CHD;HAVE_RUNAHEAD;ENABLE_HLSL;WANT_IFADDRS;HAVE_7ZIP;HAVE_CHEEVOS;HAVE_SL;FLAC_PACKAGE_VERSION="\"retroarch\"";HAVE_LROUND;FLAC__HAS_OGG=0;DONT_WANT_ARM_OPTIMIZATIONS;__STDC_LIMIT_MACROS;%(PreprocessorDefinitions) + Enabled + + + %(LibraryDependencies);GLESv2;EGL;dl;z;m;OpenSLES + + + + + + diff --git a/pkg/android/phoenix64/msvc-2017-android.NativeActivity.vcxproj.filters b/pkg/android/phoenix64/msvc-2017-android.NativeActivity.vcxproj.filters new file mode 100644 index 0000000000..3ae9a90039 --- /dev/null +++ b/pkg/android/phoenix64/msvc-2017-android.NativeActivity.vcxproj.filters @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/pkg/android/phoenix64/msvc-2017-android.Packaging.androidproj b/pkg/android/phoenix64/msvc-2017-android.Packaging.androidproj new file mode 100644 index 0000000000..e61050d3de --- /dev/null +++ b/pkg/android/phoenix64/msvc-2017-android.Packaging.androidproj @@ -0,0 +1,154 @@ + + + + + Debug + ARM + + + Release + ARM + + + Debug + ARM64 + + + Release + ARM64 + + + Debug + x64 + + + Release + x64 + + + Debug + x86 + + + Release + x86 + + + + retroarch-activity + 14.0 + 1.0 + {94b52983-76de-4545-a708-433c377727c7} + + + + true + Application + + + false + Application + + + true + Application + + + false + Application + + + true + Application + + + false + Application + + + true + Application + + + false + Application + + + + + + + + + $(RootNamespace) + + + + + $(RootNamespace) + + + + + $(RootNamespace) + + + + + $(RootNamespace) + + + + + $(RootNamespace) + + + + + $(RootNamespace) + + + + + $(RootNamespace) + + + + + $(RootNamespace) + + + + + + + + + {e27d73ec-6148-4817-b75c-adaa0c563939} + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkg/android/phoenix64/msvc-2017-android.sln b/pkg/android/phoenix64/msvc-2017-android.sln new file mode 100644 index 0000000000..45919ce71c --- /dev/null +++ b/pkg/android/phoenix64/msvc-2017-android.sln @@ -0,0 +1,72 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.9 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "msvc-2017-android", "msvc-2017-android", "{82FC602D-4083-4ED5-858B-A066A4280E4C}" +EndProject +Project("{39E2626F-3545-4960-A6E8-258AD8476CE5}") = "msvc-2017-android.Packaging", "msvc-2017-android.Packaging.androidproj", "{94B52983-76DE-4545-A708-433C377727C7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc-2017-android.NativeActivity", "msvc-2017-android.NativeActivity.vcxproj", "{E27D73EC-6148-4817-B75C-ADAA0C563939}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {94B52983-76DE-4545-A708-433C377727C7}.Debug|ARM.ActiveCfg = Debug|ARM + {94B52983-76DE-4545-A708-433C377727C7}.Debug|ARM.Build.0 = Debug|ARM + {94B52983-76DE-4545-A708-433C377727C7}.Debug|ARM.Deploy.0 = Debug|ARM + {94B52983-76DE-4545-A708-433C377727C7}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {94B52983-76DE-4545-A708-433C377727C7}.Debug|ARM64.Build.0 = Debug|ARM64 + {94B52983-76DE-4545-A708-433C377727C7}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {94B52983-76DE-4545-A708-433C377727C7}.Debug|x64.ActiveCfg = Debug|x64 + {94B52983-76DE-4545-A708-433C377727C7}.Debug|x64.Build.0 = Debug|x64 + {94B52983-76DE-4545-A708-433C377727C7}.Debug|x64.Deploy.0 = Debug|x64 + {94B52983-76DE-4545-A708-433C377727C7}.Debug|x86.ActiveCfg = Debug|x86 + {94B52983-76DE-4545-A708-433C377727C7}.Debug|x86.Build.0 = Debug|x86 + {94B52983-76DE-4545-A708-433C377727C7}.Debug|x86.Deploy.0 = Debug|x86 + {94B52983-76DE-4545-A708-433C377727C7}.Release|ARM.ActiveCfg = Release|ARM + {94B52983-76DE-4545-A708-433C377727C7}.Release|ARM.Build.0 = Release|ARM + {94B52983-76DE-4545-A708-433C377727C7}.Release|ARM.Deploy.0 = Release|ARM + {94B52983-76DE-4545-A708-433C377727C7}.Release|ARM64.ActiveCfg = Release|ARM64 + {94B52983-76DE-4545-A708-433C377727C7}.Release|ARM64.Build.0 = Release|ARM64 + {94B52983-76DE-4545-A708-433C377727C7}.Release|ARM64.Deploy.0 = Release|ARM64 + {94B52983-76DE-4545-A708-433C377727C7}.Release|x64.ActiveCfg = Release|x64 + {94B52983-76DE-4545-A708-433C377727C7}.Release|x64.Build.0 = Release|x64 + {94B52983-76DE-4545-A708-433C377727C7}.Release|x64.Deploy.0 = Release|x64 + {94B52983-76DE-4545-A708-433C377727C7}.Release|x86.ActiveCfg = Release|x86 + {94B52983-76DE-4545-A708-433C377727C7}.Release|x86.Build.0 = Release|x86 + {94B52983-76DE-4545-A708-433C377727C7}.Release|x86.Deploy.0 = Release|x86 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Debug|ARM.ActiveCfg = Debug|ARM + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Debug|ARM.Build.0 = Debug|ARM + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Debug|ARM64.Build.0 = Debug|ARM64 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Debug|x64.ActiveCfg = Debug|x64 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Debug|x64.Build.0 = Debug|x64 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Debug|x86.ActiveCfg = Debug|x86 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Debug|x86.Build.0 = Debug|x86 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Release|ARM.ActiveCfg = Release|ARM + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Release|ARM.Build.0 = Release|ARM + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Release|ARM64.ActiveCfg = Release|ARM64 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Release|ARM64.Build.0 = Release|ARM64 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Release|x64.ActiveCfg = Release|x64 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Release|x64.Build.0 = Release|x64 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Release|x86.ActiveCfg = Release|x86 + {E27D73EC-6148-4817-B75C-ADAA0C563939}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {94B52983-76DE-4545-A708-433C377727C7} = {82FC602D-4083-4ED5-858B-A066A4280E4C} + {E27D73EC-6148-4817-B75C-ADAA0C563939} = {82FC602D-4083-4ED5-858B-A066A4280E4C} + EndGlobalSection +EndGlobal diff --git a/pkg/android/phoenix64/proguard-project.txt b/pkg/android/phoenix64/proguard-project.txt new file mode 100644 index 0000000000..f2fe1559a2 --- /dev/null +++ b/pkg/android/phoenix64/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/pkg/android/phoenix64/project.properties b/pkg/android/phoenix64/project.properties new file mode 100644 index 0000000000..93ee842b0e --- /dev/null +++ b/pkg/android/phoenix64/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-24 +android.library.reference.1=libs/googleplay diff --git a/pkg/android/phoenix64/res/drawable-hdpi/ic_launcher.png b/pkg/android/phoenix64/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d33d1953f9b1d04db50391c6bac98141921050f0 GIT binary patch literal 1329 zcmV-118o96bJC*&m?vdG;s?A1&Va=AVSc+q`1m}h5(UaFI@x+=ww0YDhORV$Qlx$h!nI1 zT9}?|dFo>B6@kut0lt7<;J(1=AYS(JLo!M8ODYfWpG1+oKizvs37`PVDyyur$|`G< zYs=2Iot-rg9|s@TqiP!fb`?c=C(H7WilTgwW%=VeM^TgycHRNNu06)sID7Sa{ZCa@ zaT8Oo*Z%>4y*Nl)0I*9beV_Lr(hjBcy*-m6Ew^m|*e8Vil=lEK0QwmKo=f4F^8%xSWLM?LdYcV0i+#5$OHfmA;L1_K+pe2K+j>(tV09s0l*7F z$mhHVkO9zV0C-UXl|Us>2~+|VFeOk4v;jcPW)siP&z;2GPZIkmB#^4AXcz|a8jVJg z-#?j5ocHUxjwdH4n+4QtHqo-ISV*JM2pMCDh-g_BHX042l%g!ln*+p=_&^a6d%fO+ z@9A_p&U+YR*lxFxQtITfNQDAYRTX=^o&&@f!;6cHP&kN){eIttlLS&KK&ELTV+);%Qm4~#ow#Y5czJp0OVsN3``GPvT@eS5xR@bcq`SL2=XG7zoxa795(hF( z({<7!5FrG|(jr;q1U%XeIEP)tfsO!2f;yLj?#8a(Se@hHV>_1^EOQ0|% z_Myaq#QqbuEX%^{>uXmuO^duAP1AhwHt8_s?L&zHdDrqfm)M6A0}}hsx|i685(Db> zdVx)uC(iOqs|>>kY}P!f0I8~ql+wV4O9;W?aG1A?Q{w&5LrD~96_WS;uI1{RaI0J zr4TrU1xgcXV}Q~?ii-1CpiG_@OA09tjt%r{9H3nQIFuymyR?ClK#Gea%Q8xm)P=)&2&6ui(FDRzm}A!{SNcF96`{N~Q8cwOakXTCM(( zW+X|{DwWDjlt_}K#mM#X@$vUZM@N!9#>h`S^JR7b0IvYx4FG%t0B-@{+cnQydn|A4 zu^m8+=jH+Ie_jB9X8`ch-q~vaI9l_(w#V|)9$Tz`UJ#LX0bm~%)9|Ui({;{Mdo26# n$p7x(wFTwBzm!#0S?ScjE;XFU#%3qB00000NkvXXu0mjfLn3pG literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/res/drawable-ldpi/ic_launcher.png b/pkg/android/phoenix64/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..555fbd7685f26473a95b1f3899ec7b6ee3fa6c5e GIT binary patch literal 690 zcmV;j0!{siP)#TP3DO(qjWgm$~VaGuZSi=d%Uh)^g*CX=yD9u9{| zrBcM>@gsJiUfHhltSacClPPRs;BIaCdA3VesPpe%~@? zB9Q>N{nx<=plQ};rN`qDzuzyj*-Xac@k*Y{<&sDwBGc(qMx)U>yIV9hIdD&{kjv#F z7!0zF-L-540)eF!RRujX&YBU>1RemCN~NufF|Y^h0MCIju)Fq&yzSw3y8*7Aszn^f zl9?_=uh(1fDwWDI%KJ@Q%DH1b3LF0Q!C-)hkV>U&`KNBE>xfZ&o~F}j)$iTb#gs}V zfX65Cb-Ue&2tJ<=<36>Km|cK;KL1_U^?l&cDPp`X7K>kMwc0mh{dk?bu>%JV9Q?2N Y4fe3ozoLd_yZ`_I07*qoM6N<$g2W^{m;e9( literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/res/drawable-mdpi/ic_launcher.png b/pkg/android/phoenix64/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a338dfb2f9e9657505c316aeb70254359fbe6d09 GIT binary patch literal 853 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 DnS>gY literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/res/drawable-xhdpi/ic_launcher.png b/pkg/android/phoenix64/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..7eb088dc92430c280f73fefbc27acb048035b0e2 GIT binary patch literal 1678 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 GV*d?_DN<+v literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/res/drawable/banner.png b/pkg/android/phoenix64/res/drawable/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..bcf43ef5aae716ad41a273bad6688c3a3e4fe558 GIT binary patch literal 4423 zcmcgw`y-S6``?Ut9EMWNwn%b{*mBrHJaUK}a!8gIn?nklG2vlYWP}nGiu53Qa$E;2 zhfK>^DkW#;l=QSP=W_VmKA-R3@cm)i{l2c(^}4V3>-~P;*LClPljA9vI6@o*0>Nx; zEL}h#@Sni-%RhvG?*OK^HShzbxtux)s_a3{0Rv%wa|d$}=vlhNCP@Ssi&1UP(?CLx z_U(Sa7lLau0i!~g6+X;0_)=H|Dbx={C0(I}=}`Q_4(jWmbuj1(ad8d^BvWf^X?`}+ zlRvr>eAW%owz!o_@EtBLCR=XwdYF@JweGei4xBazS6_DDCuV(f`|%BN@3R4gH;9s! zAC#8eRS^ard!1QonFe5I{hH50BH@o7{+=5p8PR6*XiX1iduCV4jBE8~O@qI^kpJej zZEYEVAs%XhqcglEb8IkB`^RvInoAm3RwMt9Z{T%6hxIsg0MHQm=k1Q?{8wTl!X%UdXV~)6-iUp`BU%FW|?(Gl;W?H+K=k zGih9GMJ6BYot~cl-dFYlwKg{9xly<-$gn$b(vGCKAGb+h8>SywU$Yh7;5o16fi3vOF%-W+n zK4;<5$naLilKQwJGPWt|#{g#IfNo<5Hf}n4;!UDk*|~zI!z>b3azJ9ZhFl-Da%3_& zY<*z@NntA&hh(Qtby;TC*7uuecVGbDU7)0> zxXrH}-_9|>U@!)OQBl9VJBsbHE4z>VmHZv*bhYqq%nskC~kprn+((YOq3 zwxmESqtNMOx-uUouT11NJvq|lFTt;AwWHw|77~{Y0Ss4Uz0cjtitSfULCW*G z+YzWR)e(fDSHhy-=UxA>2s?g*JSCKOp9qsWt{+qlP14`BCjs^j@`buEO(5!eAho?_ zVs$mV%mDYek~9iN>TtZ`whX*03V!a!KBK~<1`SON4Vi&f;{CkamCUQ6D1UIJOw2GF z)KC&hmcRUzc-Hl`dgNBKKNhuiqXn-bd2IE6GVmh4tM<}^`p^^T6 z^`_0X#o0%3lOCp5D3n&h`};u~XV#InsudL#>$#^@o5$H6wUh%oz9rugsAE@fJqVPb zfz$$4uLrqnG?8m0SoA5%VP#Blf=Cc!SAA& zZk(Lte=)od*C3(`QF=6_V>pmgFRPOgGK~3XwVwh$mov!Y5d~!j|h2-^&w8aJ2Q`2q>W^048-0o7aj! zb=Hz%z|pTk5_cFOOMyhrOi(}1X@Ghf(5sEPA_7eFjJMtF?bb`+xwUc z_+jZxS9U~JSVTmZu8T4~KhyXp8}jIh@5=YSb(<3>*2d$^bf#-9zwn%fV1eTJ79sl~ zRp2zckns*2L7A~sj)tFrEHY_l69p?1!*>bUi`?cRP^X`g48UcPLiR1Ue;~BK-h2F! z^?>mT_|jNwka<zD z7iL}6cesyrYd5rYvZ`65y2cW5P6jPc?6k@=fZzNg+e8up)4(MJTvhWwpX|Gt`*(># zCmNtC4n83ObV1&Wel6~mwu9NurruBFUuP(ClnW0`cQ$GJt^lb9IZ}fB5pByU z*kO1snHwM^H)rr;mB!H2rI?{L-M;CHo!gb`@n_ajx_MzkWHq#?VLAs}u1(Ca<`Niv zA=}q%Z&=W5^@8wToI{Ju(O4<;O#8$v^a;4SnERM?51cBD4BtM^xvQe|g&3AqQU?o! z;Scu#Q!gHgrBLH#&UY3f&!Jd0k4b|i=sk~5zYatTIxQ`^br88lbawIiVtnVmA3orFGSDo_h3ITEaZ!K&tDO?4Vl$AER4Psn2=S^&wqbw$FgE&kF9W;=l;%9yV}f!Q;Nw5UxPL&8f&;$Hwl;$W@;e02Tr zWi|sW!DY_K&l?1OSzcMG$i3QsF=Fe5@7AxCi1!E-Y6O3YW^kbD_@J3J28oRaP-r(%x>gw9q*vP(q@^XuN zA`H(qNc%09-d)Evdwz98Fatvx^7eXWjzeY~Ci#dvMGLF$#dR_%RVgSIiwwse&9AAc zaed-QiX@wCOy6N&Z_AII6l=JM1eTxA=d-UX{`1yHL>ixiP0N)7x`s1mTl;(hryfR( zHLEs60JXc}3i46R>UmdJS)Bs#-o*=x5IHs2R7s19=&!Npc@mLK-TQgw<*oJI^=7&!uWRLle%eG{T8P*=J)EvUPTKO zLjN@9P$3BrA)G&ys9cRXaia0kI|Sk6J>&TX*D(`Q=FQRih^f7=PXbUUPGJC-ePvM+ z27A}tO*~095wxoS(g1aS9d0=Nw;_4xy4|{{pT86<$ zZEoVHOox(`Vw2MYG^>)h#p1v#(2h^vLWx7}h~h@R(bdxG>izDT|72xl-BCX?2^nsm znLr=)&O9e=)om)=)$5=nuJh}=+|ljvvy1Cf={^C7v7U# z(@=HbsNzOS?O2qAtA%Rt>kYMAtu8LoNtpRWE+Y^)`kUD|Gcq#xs$4F2PkIsJ4k{UC zM>P#~!X49tKp^ZCEy?IT7@kJxpK!2?7JRwTn{%~Yfh1$|g!myf1>CRRcK!T8a=fN4 z8X9EjC@yOrC9L8ZBsp*wCHFO6|BtWr3viamab0`Sjid0N)*J@EJ%eQ3?$b=g3PFP$ z9AQ2uJ;l}P&Cx{pP%2zbV2}QCGXZRz`GVVi8ykP0q9Hl(5Tyi7GLexCDei03dRFJf znCuJ;?{LR8@8=q_%`(_y&^+{US4sI|?HnGojd4f4EoD#9XW=P3N!=WzYg=IHvv zaH_{N6+^lE50R?LVYnWiO)V(8F6?Tj49(Ly?wzKns+{8?j^Tao(DeDGkx%q}ih}gS zqx3J`CWtJZ-Vdi*PnTnE`0B#XJxB%npSp!yvN4ReEiQ#qOQzpq?)hrxoGncO`#VS- zNU(**V~RcCRH^9^O#VL29Oo1cV@df`x^gih9$b7`5{C`_1$TR(lH*vK3ZAv4fS_5G z^7iU|Eex948c5IXMf}IZvXZ#CP$c@*+o+1}+%+%!NSB=C$GP3VOhC3)j+T`tiShpd DnS>gY literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/mainmenu/MainMenuActivity.java b/pkg/android/phoenix64/src/com/retroarch/browser/mainmenu/MainMenuActivity.java new file mode 100644 index 0000000000..102dffdf50 --- /dev/null +++ b/pkg/android/phoenix64/src/com/retroarch/browser/mainmenu/MainMenuActivity.java @@ -0,0 +1,200 @@ +package com.retroarch.browser.mainmenu; + +import com.retroarch.browser.preferences.util.UserPreferences; +import com.retroarch.browser.retroactivity.RetroActivityFuture; +import com.retroarch.browser.retroactivity.RetroActivityPast; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; +import android.media.AudioManager; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.preference.PreferenceActivity; +import android.preference.PreferenceManager; +import android.provider.Settings; + +import java.util.List; +import java.util.ArrayList; +import android.content.pm.PackageManager; +import android.Manifest; +import android.content.DialogInterface; +import android.app.AlertDialog; +import android.util.Log; + +/** + * {@link PreferenceActivity} subclass that provides all of the + * functionality of the main menu screen. + */ +public final class MainMenuActivity extends PreferenceActivity +{ + final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124; + boolean checkPermissions = false; + + public void showMessageOKCancel(String message, DialogInterface.OnClickListener onClickListener) + { + new AlertDialog.Builder(this).setMessage(message) + .setPositiveButton("OK", onClickListener).setCancelable(false) + .setNegativeButton("Cancel", null).create().show(); + } + + private boolean addPermission(List permissionsList, String permission) + { + if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) + { + permissionsList.add(permission); + + // Check for Rationale Option + if (!shouldShowRequestPermissionRationale(permission)) + return false; + } + + return true; + } + + public void checkRuntimePermissions() + { + if (android.os.Build.VERSION.SDK_INT >= 23) + { + // Android 6.0+ needs runtime permission checks + List permissionsNeeded = new ArrayList(); + final List permissionsList = new ArrayList(); + + if (!addPermission(permissionsList, Manifest.permission.READ_EXTERNAL_STORAGE)) + permissionsNeeded.add("Read External Storage"); + if (!addPermission(permissionsList, Manifest.permission.WRITE_EXTERNAL_STORAGE)) + permissionsNeeded.add("Write External Storage"); + + if (permissionsList.size() > 0) + { + checkPermissions = true; + + if (permissionsNeeded.size() > 0) + { + // Need Rationale + Log.i("MainMenuActivity", "Need to request external storage permissions."); + + String message = "You need to grant access to " + permissionsNeeded.get(0); + + for (int i = 1; i < permissionsNeeded.size(); i++) + message = message + ", " + permissionsNeeded.get(i); + + showMessageOKCancel(message, + new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + if (which == AlertDialog.BUTTON_POSITIVE) + { + requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), + REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS); + + Log.i("MainMenuActivity", "User accepted request for external storage permissions."); + } + } + }); + } + else + { + requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), + REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS); + + Log.i("MainMenuActivity", "Requested external storage permissions."); + } + } + } + + if (!checkPermissions) + { + finalStartup(); + } + } + + public void finalStartup() + { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + Intent retro; + + if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) + { + retro = new Intent(this, RetroActivityFuture.class); + } + else + { + retro = new Intent(this, RetroActivityPast.class); + } + + retro.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + + startRetroActivity( + retro, + null, + prefs.getString("libretro_path", getApplicationInfo().dataDir + "/cores/"), + UserPreferences.getDefaultConfigPath(this), + Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD), + getApplicationInfo().dataDir, + getApplicationInfo().sourceDir); + startActivity(retro); + finish(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) + { + switch (requestCode) + { + case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: + for (int i = 0; i < permissions.length; i++) + { + if(grantResults[i] == PackageManager.PERMISSION_GRANTED) + { + Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was granted."); + } + else + { + Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was not granted."); + } + } + + break; + default: + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + break; + } + + finalStartup(); + } + + public static void startRetroActivity(Intent retro, String contentPath, String corePath, + String configFilePath, String imePath, String dataDirPath, String dataSourcePath) + { + if (contentPath != null) { + retro.putExtra("ROM", contentPath); + } + retro.putExtra("LIBRETRO", corePath); + retro.putExtra("CONFIGFILE", configFilePath); + retro.putExtra("IME", imePath); + retro.putExtra("DATADIR", dataDirPath); + retro.putExtra("APK", dataSourcePath); + retro.putExtra("SDCARD", Environment.getExternalStorageDirectory().getAbsolutePath()); + retro.putExtra("DOWNLOADS", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()); + retro.putExtra("SCREENSHOTS", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()); + String external = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/com.retroarch.aarch64/files"; + retro.putExtra("EXTERNAL", external); + } + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + // Bind audio stream to hardware controls. + setVolumeControlStream(AudioManager.STREAM_MUSIC); + + UserPreferences.updateConfigFile(this); + + checkRuntimePermissions(); + } +} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/ConfigFile.java b/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/ConfigFile.java new file mode 100644 index 0000000000..eccaf730cb --- /dev/null +++ b/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/ConfigFile.java @@ -0,0 +1,281 @@ +package com.retroarch.browser.preferences.util; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +import android.util.Log; + +/** + * Represents a configuration file that works off of a key-value pair + * in the form [key name] = "[value]". + */ +public final class ConfigFile +{ + // Map containing all of the key-value pairs. + private final HashMap map = new HashMap(); + + /** + * Constructor + */ + public ConfigFile() + { + } + + /** + * Constructor + * + * @param filePath The path to the configuration file to open. + */ + public ConfigFile(String filePath) + { + if (filePath == null) + throw new IllegalArgumentException("filePath cannot be null."); + + try + { + open(filePath); + } + catch (IOException ioe) + { + Log.e("ConfigFile", "Stream reading the configuration file was suddenly closed for an unknown reason."); + } + } + + /** + * Parses a configuration file from the given stream + * and appends the parsed values to the key-value map. + * + * @param stream The {@link InputStream} containing the configuration file to parse. + */ + public void append(InputStream stream) throws IOException + { + BufferedReader br = new BufferedReader(new InputStreamReader(stream)); + + String line; + while ((line = br.readLine()) != null) + parseLine(line); + + br.close(); + } + + /** + * Opens a configuration file given by configPath + * and parses all of its key-value pairs, adding + * them to the key-value map. + * + * @param configPath Path to the configuration file to parse. + */ + public void open(String configPath) throws IOException + { + clear(); + append(new FileInputStream(configPath)); + } + + private void parseLine(String line) + { + String[] tokens = line.split("=", 2); + if (tokens.length < 2) + return; + + for (int i = 0; i < tokens.length; i++) + tokens[i] = tokens[i].trim(); + + String key = tokens[0]; + String value = tokens[1]; + + if (value.startsWith("\"")) + value = value.substring(1, value.lastIndexOf('\"')); + else + value = value.split(" ")[0]; + + if (value.length() > 0) + map.put(key, value); + } + + /** + * Clears the key-value map of all currently set keys and values. + */ + public void clear() + { + map.clear(); + } + + /** + * Writes the currently set key-value pairs to + * + * @param path The path to save the + * + * @throws IOException + */ + public void write(String path) throws IOException + { + PrintWriter writer = new PrintWriter(path); + + for (Map.Entry entry : map.entrySet()) + { + writer.println(entry.getKey() + " = \"" + entry.getValue() + "\""); + } + + writer.close(); + } + + /** + * Checks if a key exists in the {@link HashMap} + * backing this ConfigFile instance. + * + * @param key The key to check for. + * + * @return true if the key exists in the HashMap backing + * this ConfigFile; false if it doesn't. + */ + public boolean keyExists(String key) + { + return map.containsKey(key); + } + + /** + * Sets a key to the given String value. + * + * @param key The key to set the String value to. + * @param value The String value to set to the key. + */ + public void setString(String key, String value) + { + map.put(key, value); + } + + /** + * Sets a key to the given boolean value. + * + * @param key The key to set the boolean value to. + * @param value The boolean value to set to the key. + */ + public void setBoolean(String key, boolean value) + { + map.put(key, Boolean.toString(value)); + } + + /** + * Sets a key to the given Integer value. + * + * @param key The key to set the Integer value to. + * @param value The Integer value to set to the key. + */ + public void setInt(String key, int value) + { + map.put(key, Integer.toString(value)); + } + + /** + * Sets a key to the given double value. + * + * @param key The key to set the double value to. + * @param value The double value to set to the key. + */ + public void setDouble(String key, double value) + { + map.put(key, Double.toString(value)); + } + + /** + * Sets a key to the given float value. + * + * @param key The key to set the float value to. + * @param value The float value to set to the key. + */ + public void setFloat(String key, float value) + { + map.put(key, Float.toString(value)); + } + + /** + * Gets the String value associated with the given key. + * + * @param key The key to get the String value from. + * + * @return the String object associated with the given key. + */ + public String getString(String key) + { + String ret = map.get(key); + + if (ret != null) + return ret; + else + return null; + } + + /** + * Gets the Integer value associated with the given key. + * + * @param key The key to get the Integer value from. + * + * @return the Integer value associated with the given key. + */ + public int getInt(String key) + { + String str = getString(key); + + if (str != null) + return Integer.parseInt(str); + else + throw new IllegalArgumentException("Config key '" + key + "' is invalid."); + } + + /** + * Gets the double value associated with the given key. + * + * @param key The key to get the double value from. + * + * @return the double value associated with the given key. + */ + public double getDouble(String key) + { + String str = getString(key); + + if (str != null) + return Double.parseDouble(str); + else + throw new IllegalArgumentException("Config key '" + key + "' is invalid."); + } + + /** + * Gets the float value associated with the given key. + * + * @param key The key to get the float value from. + * + * @return the float value associated with the given key. + */ + public float getFloat(String key) + { + String str = getString(key); + + if (str != null) + return Float.parseFloat(str); + else + throw new IllegalArgumentException("Config key '" + key + "' is invalid."); + } + + /** + * Gets the boolean value associated with the given key. + * + * @param key The key to get the boolean value from. + * + * @return the boolean value associated with the given key. + */ + public boolean getBoolean(String key) + { + String str = getString(key); + + if (str != null) + return Boolean.parseBoolean(str); + else + throw new IllegalArgumentException("Config key '" + key + "' is invalid."); + } +} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/UserPreferences.java b/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/UserPreferences.java new file mode 100644 index 0000000000..2e1ec9ed61 --- /dev/null +++ b/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/UserPreferences.java @@ -0,0 +1,300 @@ +package com.retroarch.browser.preferences.util; + +import java.io.File; +import java.io.IOException; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.SharedPreferences; +import android.media.AudioManager; +import android.media.AudioTrack; +import android.os.Build; +import android.preference.PreferenceManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.util.Log; + +/** + * Utility class for retrieving, saving, or loading preferences. + */ +public final class UserPreferences +{ + // Logging tag. + private static final String TAG = "UserPreferences"; + + // Disallow explicit instantiation. + private UserPreferences() + { + } + + /** + * Retrieves the path to the default location of the libretro config. + * + * @param ctx the current {@link Context} + * + * @return the path to the default location of the libretro config. + */ + public static String getDefaultConfigPath(Context ctx) + { + // Internal/External storage dirs. + final String internal = ctx.getFilesDir().getAbsolutePath(); + String external = null; + + // Get the App's external storage folder + final String state = android.os.Environment.getExternalStorageState(); + if (android.os.Environment.MEDIA_MOUNTED.equals(state)) { + File extsd = ctx.getExternalFilesDir(null); + external = extsd.getAbsolutePath(); + } + + // Native library directory and data directory for this front-end. + final String dataDir = ctx.getApplicationInfo().dataDir; + final String coreDir = dataDir + "/cores/"; + + // Get libretro name and path + final SharedPreferences prefs = getPreferences(ctx); + final String libretro_path = prefs.getString("libretro_path", coreDir); + + // Check if global config is being used. Return true upon failure. + final boolean globalConfigEnabled = prefs.getBoolean("global_config_enable", true); + + String append_path; + // If we aren't using the global config. + if (!globalConfigEnabled && !libretro_path.equals(coreDir)) + { + String sanitized_name = sanitizeLibretroPath(libretro_path); + append_path = File.separator + sanitized_name + ".cfg"; + } + else // Using global config. + { + append_path = File.separator + "retroarch.cfg"; + } + + if (external != null) + { + String confPath = external + append_path; + if (new File(confPath).exists()) + return confPath; + } + else if (internal != null) + { + String confPath = internal + append_path; + if (new File(confPath).exists()) + return confPath; + } + else + { + String confPath = "/mnt/extsd" + append_path; + if (new File(confPath).exists()) + return confPath; + } + + // Config file does not exist. Create empty one. + + // emergency fallback + String new_path = "/mnt/sd" + append_path; + + if (external != null) + new_path = external + append_path; + else if (internal != null) + new_path = internal + append_path; + else if (dataDir != null) + new_path = dataDir + append_path; + + try { + new File(new_path).createNewFile(); + } + catch (IOException e) + { + Log.e(TAG, "Failed to create config file to: " + new_path); + } + return new_path; + } + + /** + * Updates the libretro configuration file + * with new values if settings have changed. + * + * @param ctx the current {@link Context}. + */ + public static void updateConfigFile(Context ctx) + { + String path = getDefaultConfigPath(ctx); + ConfigFile config = new ConfigFile(path); + + Log.i(TAG, "Writing config to: " + path); + + final String dataDir = ctx.getApplicationInfo().dataDir; + final String coreDir = dataDir + "/cores/"; + + final SharedPreferences prefs = getPreferences(ctx); + + config.setString("libretro_directory", coreDir); + config.setInt("audio_out_rate", getOptimalSamplingRate(ctx)); + + try + { + int version = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0).versionCode; + final String dst_path = dataDir; + final String dst_path_subdir = "assets"; + + Log.i(TAG, "dst dir is: " + dst_path); + Log.i(TAG, "dst subdir is: " + dst_path_subdir); + + config.setBoolean("log_verbosity", true); + config.setString("bundle_assets_src_path", ctx.getApplicationInfo().sourceDir); + config.setString("bundle_assets_dst_path", dst_path); + config.setString("bundle_assets_dst_path_subdir", dst_path_subdir); + config.setInt("bundle_assets_extract_version_current", version); + } + catch (NameNotFoundException ignored) + { + } + + // Refactor this entire mess and make this usable for per-core config + if (Build.VERSION.SDK_INT >= 17 && prefs.getBoolean("audio_latency_auto", true)) + { + config.setInt("audio_block_frames", getLowLatencyBufferSize(ctx)); + } + + try + { + config.write(path); + } + catch (IOException e) + { + Log.e(TAG, "Failed to save config file to: " + path); + } + } + + private static void readbackString(ConfigFile cfg, SharedPreferences.Editor edit, String key) + { + if (cfg.keyExists(key)) + edit.putString(key, cfg.getString(key)); + else + edit.remove(key); + } + + private static void readbackBool(ConfigFile cfg, SharedPreferences.Editor edit, String key) + { + if (cfg.keyExists(key)) + edit.putBoolean(key, cfg.getBoolean(key)); + else + edit.remove(key); + } + + private static void readbackDouble(ConfigFile cfg, SharedPreferences.Editor edit, String key) + { + if (cfg.keyExists(key)) + edit.putFloat(key, (float)cfg.getDouble(key)); + else + edit.remove(key); + } + + /* + private static void readbackFloat(ConfigFile cfg, SharedPreferences.Editor edit, String key) + { + if (cfg.keyExists(key)) + edit.putFloat(key, cfg.getFloat(key)); + else + edit.remove(key); + } + */ + + /** + private static void readbackInt(ConfigFile cfg, SharedPreferences.Editor edit, String key) + { + if (cfg.keyExists(key)) + edit.putInt(key, cfg.getInt(key)); + else + edit.remove(key); + } + */ + + /** + * Sanitizes a libretro core path. + * + * @param path The path to the libretro core. + * + * @return the sanitized libretro path. + */ + private static String sanitizeLibretroPath(String path) + { + String sanitized_name = path.substring( + path.lastIndexOf('/') + 1, + path.lastIndexOf('.')); + sanitized_name = sanitized_name.replace("neon", ""); + sanitized_name = sanitized_name.replace("libretro_", ""); + + return sanitized_name; + } + + /** + * Gets a {@link SharedPreferences} instance containing current settings. + * + * @param ctx the current {@link Context}. + * + * @return A SharedPreference instance containing current settings. + */ + public static SharedPreferences getPreferences(Context ctx) + { + return PreferenceManager.getDefaultSharedPreferences(ctx); + } + + /** + * Gets the optimal sampling rate for low-latency audio playback. + * + * @param ctx the current {@link Context}. + * + * @return the optimal sampling rate for low-latency audio playback in Hz. + */ + @TargetApi(17) + private static int getLowLatencyOptimalSamplingRate(Context ctx) + { + AudioManager manager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE); + + return Integer.parseInt(manager + .getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)); + } + + /** + * Gets the optimal buffer size for low-latency audio playback. + * + * @param ctx the current {@link Context}. + * + * @return the optimal output buffer size in decimal PCM frames. + */ + @TargetApi(17) + private static int getLowLatencyBufferSize(Context ctx) + { + AudioManager manager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE); + int buffersize = Integer.parseInt(manager + .getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER)); + Log.i(TAG, "Queried ideal buffer size (frames): " + buffersize); + return buffersize; + } + + /** + * Gets the optimal audio sampling rate. + *

+ * On Android 4.2+ devices this will retrieve the optimal low-latency sampling rate, + * since Android 4.2 adds support for low latency audio in general. + *

+ * On other devices, it simply returns the regular optimal sampling rate + * as returned by the hardware. + * + * @param ctx The current {@link Context}. + * + * @return the optimal audio sampling rate in Hz. + */ + private static int getOptimalSamplingRate(Context ctx) + { + int ret; + if (Build.VERSION.SDK_INT >= 17) + ret = getLowLatencyOptimalSamplingRate(ctx); + else + ret = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC); + + Log.i(TAG, "Using sampling rate: " + ret + " Hz"); + return ret; + } +} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java new file mode 100644 index 0000000000..d51d7f768f --- /dev/null +++ b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java @@ -0,0 +1,225 @@ +package com.retroarch.browser.retroactivity; + +import java.io.IOException; + +import com.retroarch.browser.preferences.util.UserPreferences; + +import android.annotation.SuppressLint; +import android.content.SharedPreferences; +import android.graphics.SurfaceTexture; +import android.graphics.SurfaceTexture.OnFrameAvailableListener; +import android.hardware.Camera; +import android.os.Build; +import android.os.Bundle; +import android.util.Log; + +//For Android 3.0 and up + +/** + * Class which provides {@link Camera} functionality + * to {@link RetroActivityFuture}. + */ +@SuppressLint("NewApi") +public class RetroActivityCamera extends RetroActivityCommon +{ + private Camera mCamera = null; + private long lastTimestamp = 0; + private SurfaceTexture texture; + private boolean updateSurface = true; + private boolean camera_service_running = false; + + /** + * Executed when the {@link Camera} + * is staring to capture. + */ + public void onCameraStart() + { + if (camera_service_running) + return; + + if (mCamera != null) + mCamera.startPreview(); + camera_service_running = true; + } + + /** + * Executed when the {@link Camera} is done capturing. + *

+ * Note that this does not release the currently held + * {@link Camera} instance and must be freed by calling + * {@link #onCameraFree} + */ + public void onCameraStop() + { + if (!camera_service_running) + return; + + if (mCamera != null) + mCamera.stopPreview(); + camera_service_running = false; + } + + /** + * Releases the currently held {@link Camera} instance. + */ + public void onCameraFree() + { + onCameraStop(); + + if (mCamera != null) + mCamera.release(); + } + + /** + * Initializes the camera for use. + */ + public void onCameraInit() + { + if (mCamera != null) + return; + + mCamera = Camera.open(); + } + + /** + * Polls the camera for updates to the {@link SurfaceTexture}. + * + * @return true if polling was successful, false otherwise. + */ + public boolean onCameraPoll() + { + if (!camera_service_running) + return false; + + if (texture == null) + { + Log.i("RetroActivity", "No texture"); + return true; + } + else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) + { + if (updateSurface) + { + texture.updateTexImage(); + } + + long newTimestamp = texture.getTimestamp(); + + if (newTimestamp != lastTimestamp) + { + lastTimestamp = newTimestamp; + return true; + } + + return false; + } + + return true; + } + + /** + * Initializes the {@link SurfaceTexture} used by the + * {@link Camera} with a given OpenGL texure ID. + * + * @param gl_texid texture ID to initialize the + * {@link SurfaceTexture} with. + */ + public void onCameraTextureInit(int gl_texid) + { + texture = new SurfaceTexture(gl_texid); + texture.setOnFrameAvailableListener(onCameraFrameAvailableListener); + } + + /** + * Sets the {@link Camera} texture with the texture represented + * by the given OpenGL texture ID. + * + * @param gl_texid The texture ID representing the texture to set the camera to. + * @throws IOException If setting the texture fails. + */ + public void onCameraSetTexture(int gl_texid) throws IOException + { + if (texture == null) + onCameraTextureInit(gl_texid); + + if (mCamera != null) + mCamera.setPreviewTexture(texture); + } + + private final OnFrameAvailableListener onCameraFrameAvailableListener = new OnFrameAvailableListener() + { + @Override + public void onFrameAvailable(SurfaceTexture surfaceTexture) + { + updateSurface = true; + } + }; + + @Override + public void onCreate(Bundle savedInstanceState) + { + // Save the current setting for updates + SharedPreferences prefs = UserPreferences.getPreferences(this); + SharedPreferences.Editor edit = prefs.edit(); + edit.putBoolean("CAMERA_UPDATES_ON", false); + edit.apply(); + + camera_service_running = false; + + super.onCreate(savedInstanceState); + } + + @Override + public void onPause() + { + // Save the current setting for updates + SharedPreferences prefs = UserPreferences.getPreferences(this); + SharedPreferences.Editor edit = prefs.edit(); + edit.putBoolean("CAMERA_UPDATES_ON", camera_service_running); + edit.apply(); + + onCameraStop(); + super.onPause(); + } + + @Override + public void onResume() + { + SharedPreferences prefs = UserPreferences.getPreferences(this); + SharedPreferences.Editor edit = prefs.edit(); + + /* + * Get any previous setting for camera updates + * Gets "false" if an error occurs + */ + if (prefs.contains("CAMERA_UPDATES_ON")) + { + camera_service_running = prefs.getBoolean("CAMERA_UPDATES_ON", false); + if (camera_service_running) + { + onCameraStart(); + } + } + else // Otherwise, turn off camera updates + { + edit.putBoolean("CAMERA_UPDATES_ON", false); + edit.apply(); + camera_service_running = false; + } + super.onResume(); + } + + @Override + public void onDestroy() + { + onCameraFree(); + super.onDestroy(); + } + + @Override + public void onStop() + { + onCameraStop(); + super.onStop(); + } +} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java new file mode 100644 index 0000000000..e660dd2eb9 --- /dev/null +++ b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java @@ -0,0 +1,141 @@ +package com.retroarch.browser.retroactivity; + +import com.retroarch.browser.preferences.util.UserPreferences; +import android.annotation.TargetApi; +import android.content.res.Configuration; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.app.UiModeManager; +import android.os.BatteryManager; +import android.os.Build; +import android.os.PowerManager; +import android.util.Log; + +import java.util.concurrent.CountDownLatch; + +/** + * Class which provides common methods for RetroActivity related classes. + */ +public class RetroActivityCommon extends RetroActivityLocation +{ + public static int FRONTEND_POWERSTATE_NONE = 0; + public static int FRONTEND_POWERSTATE_NO_SOURCE = 1; + public static int FRONTEND_POWERSTATE_CHARGING = 2; + public static int FRONTEND_POWERSTATE_CHARGED = 3; + public static int FRONTEND_POWERSTATE_ON_POWER_SOURCE = 4; + public boolean sustainedPerformanceMode = true; + + // Exiting cleanly from NDK seems to be nearly impossible. + // Have to use exit(0) to avoid weird things happening, even with runOnUiThread() approaches. + // Use a separate JNI function to explicitly trigger the readback. + public void onRetroArchExit() + { + finish(); + } + + @TargetApi(24) + public void setSustainedPerformanceMode(boolean on) + { + sustainedPerformanceMode = on; + + if (Build.VERSION.SDK_INT >= 24) { + if (isSustainedPerformanceModeSupported()) { + final CountDownLatch latch = new CountDownLatch(1); + + runOnUiThread(new Runnable() { + @Override + public void run() { + Log.i("RetroActivity", "setting sustained performance mode to " + sustainedPerformanceMode); + + getWindow().setSustainedPerformanceMode(sustainedPerformanceMode); + + latch.countDown(); + } + }); + + try { + latch.await(); + }catch(InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + @TargetApi(24) + public boolean isSustainedPerformanceModeSupported() + { + boolean supported = false; + + if (Build.VERSION.SDK_INT >= 24) + { + PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE); + + if (powerManager.isSustainedPerformanceModeSupported()) + supported = true; + } + + + Log.i("RetroActivity", "isSustainedPerformanceModeSupported? " + supported); + + return supported; + } + + public int getBatteryLevel() + { + IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); + // This doesn't actually register anything (or need to) because we know this particular intent is sticky and we do not specify a BroadcastReceiver anyway + Intent batteryStatus = registerReceiver(null, ifilter); + int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); + int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, 100); + + float percent = ((float)level / (float)scale) * 100.0f; + + Log.i("RetroActivity", "battery: level = " + level + ", scale = " + scale + ", percent = " + percent); + + return (int)percent; + } + + public int getPowerstate() + { + IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); + // This doesn't actually register anything (or need to) because we know this particular intent is sticky and we do not specify a BroadcastReceiver anyway + Intent batteryStatus = registerReceiver(null, ifilter); + int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + boolean hasBattery = batteryStatus.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false); + boolean isCharging = (status == BatteryManager.BATTERY_STATUS_CHARGING); + boolean isCharged = (status == BatteryManager.BATTERY_STATUS_FULL); + int powerstate = FRONTEND_POWERSTATE_NONE; + + if (isCharged) + powerstate = FRONTEND_POWERSTATE_CHARGED; + else if (isCharging) + powerstate = FRONTEND_POWERSTATE_CHARGING; + else if (!hasBattery) + powerstate = FRONTEND_POWERSTATE_NO_SOURCE; + else + powerstate = FRONTEND_POWERSTATE_ON_POWER_SOURCE; + + Log.i("RetroActivity", "power state = " + powerstate); + + return powerstate; + } + + public boolean isAndroidTV() + { + Configuration config = getResources().getConfiguration(); + UiModeManager uiModeManager = (UiModeManager)getSystemService(UI_MODE_SERVICE); + + if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) + { + Log.i("RetroActivity", "isAndroidTV == true"); + return true; + } + else + { + Log.i("RetroActivity", "isAndroidTV == false"); + return false; + } + } +} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java new file mode 100644 index 0000000000..eba29872a6 --- /dev/null +++ b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java @@ -0,0 +1,87 @@ +package com.retroarch.browser.retroactivity; + +import android.view.View; +import android.view.WindowManager; +import android.content.Intent; +import android.content.Context; +import android.hardware.input.InputManager; +import android.os.Build; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public final class RetroActivityFuture extends RetroActivityCamera { + + // If set to true then Retroarch will completely exit when it loses focus + private boolean quitfocus = false; + + @Override + public void onResume() { + super.onResume(); + + setSustainedPerformanceMode(sustainedPerformanceMode); + + if (Build.VERSION.SDK_INT >= 19) { + // Immersive mode + + // Constants from API > 14 + final int API_SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; + final int API_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; + final int API_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; + final int API_SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; + final int API_SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; + + View thisView = getWindow().getDecorView(); + thisView.setSystemUiVisibility(API_SYSTEM_UI_FLAG_LAYOUT_STABLE + | API_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | API_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | API_SYSTEM_UI_FLAG_FULLSCREEN + | API_SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + + // Check for Android UI specific parameters + Intent retro = getIntent(); + String refresh = retro.getStringExtra("REFRESH"); + + // If REFRESH parameter is provided then try to set refreshrate accordingly + if(refresh != null) { + WindowManager.LayoutParams params = getWindow().getAttributes(); + params.preferredRefreshRate = Integer.parseInt(refresh); + getWindow().setAttributes(params); + } + + // If QUITFOCUS parameter is provided then enable that Retroarch quits when focus is lost + quitfocus = retro.hasExtra("QUITFOCUS"); + + // If HIDEMOUSE parameters is provided then hide the mourse cursor + // This requires NVIDIA Android extensions (available on NVIDIA Shield), if they are not + // available then nothing will be done + if (retro.hasExtra("HIDEMOUSE")) hideMouseCursor(); + } + } + + public void hideMouseCursor() { + + // Check for NVIDIA extensions and minimum SDK version + Method mInputManager_setCursorVisibility; + try { mInputManager_setCursorVisibility = + InputManager.class.getMethod("setCursorVisibility", boolean.class); + } + catch (NoSuchMethodException ex) { + return; // Extensions were not available so do nothing + } + + // Hide the mouse cursor + InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE); + try { mInputManager_setCursorVisibility.invoke(inputManager, false); } + catch (InvocationTargetException ite) { } + catch (IllegalAccessException iae) { } + } + + @Override + public void onStop() { + super.onStop(); + + // If QUITFOCUS parameter was set then completely exit Retroarch when focus is lost + if (quitfocus) System.exit(0); + } +} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java new file mode 100644 index 0000000000..91ccc3f8a6 --- /dev/null +++ b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java @@ -0,0 +1,105 @@ +package com.retroarch.browser.retroactivity; + +import com.retroarch.browser.mainmenu.MainMenuActivity; + +import android.content.Intent; +import android.util.Log; + +public class RetroActivityIntent extends RetroActivityCommon { + private Intent pendingIntent = null; + private static final String TAG = "RetroArch"; + + @Override + public void onBackPressed() + { + Log.i("RetroActivity", "onBackKeyPressed"); + Intent retro = new Intent(this, MainMenuActivity.class); + retro.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + startActivity(retro); + } + + @Override + public void onNewIntent(Intent intent) + { + Log.i("RetroActivity", "onNewIntent invoked."); + super.onNewIntent(intent); + setIntent(intent); + pendingIntent = intent; + } + + /** + * Gets the ROM file specified in the pending intent. + * + * @return the ROM file specified in the pending intent. + */ + public String getPendingIntentFullPath() + { + return pendingIntent.getStringExtra("ROM"); + } + + /** + * Gets the specified path to the libretro core in the pending intent. + * + * @return the specified path to the libretro core in the pending intent. + */ + public String getPendingIntentLibretroPath() + { + return pendingIntent.getStringExtra("LIBRETRO"); + } + + /** + * Gets the path specified in the pending intent to the retroarch cfg file. + * + * @return the path specified in the pending intent to the retroarch cfg file. + */ + public String getPendingIntentConfigPath() + { + return pendingIntent.getStringExtra("CONFIGFILE"); + } + + public String getPendingIntentStorageLocation() + { + return pendingIntent.getStringExtra("SDCARD"); + } + + public String getPendingIntentDownloadLocation() + { + return pendingIntent.getStringExtra("DOWNLOADS"); + } + + public String getPendingIntentScreenshotsLocation() + { + return pendingIntent.getStringExtra("SCREENSHOTS"); + } + + /** + * Gets the specified IME in the pending intent. + * + * @return the specified IME in the pending intent. + */ + public String getPendingIntentIME() + { + return pendingIntent.getStringExtra("IME"); + } + + /** + * Checks whether or not a pending intent exists. + * + * @return true if a pending intent exists, false otherwise. + */ + public boolean hasPendingIntent() + { + if (pendingIntent == null) + return false; + + return true; + } + + /** + * Clears the current pending intent. + */ + public void clearPendingIntent() + { + pendingIntent = null; + } +} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java new file mode 100644 index 0000000000..9fedbf2e7b --- /dev/null +++ b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java @@ -0,0 +1,316 @@ +package com.retroarch.browser.retroactivity; + +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks; +import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener; +import com.google.android.gms.location.LocationClient; +import com.google.android.gms.location.LocationListener; +import com.google.android.gms.location.LocationRequest; +import com.retroarch.browser.preferences.util.UserPreferences; + +import android.app.NativeActivity; +import android.content.IntentSender; +import android.content.SharedPreferences; +import android.location.Location; +import android.os.Bundle; +import android.util.Log; +import android.widget.Toast; + +/** + * Class that implements location-based functionality for + * the {@link RetroActivityFuture} and {@link RetroActivityPast} + * activities. + */ +public class RetroActivityLocation extends NativeActivity +implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener +{ + /* LOCATION VARIABLES */ + private static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 0; + private LocationClient mLocationClient = null; + private Location mCurrentLocation; + + // Define an object that holds accuracy and frequency parameters + LocationRequest mLocationRequest = null; + boolean mUpdatesRequested = false; + boolean locationChanged = false; + boolean location_service_running = false; + + /** + * Called by Location Services when the request to connect the + * client finishes successfully. At this point, you can + * request the current location or start periodic updates + */ + @Override + public void onConnected(Bundle dataBundle) + { + if (mLocationClient == null) + return; + + // Display the connection status + Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show(); + location_service_running = true; + + // If already requested, start periodic updates + if (mUpdatesRequested) + { + mLocationClient.requestLocationUpdates(mLocationRequest, this, null); + } + else + { + // Get last known location + mCurrentLocation = mLocationClient.getLastLocation(); + locationChanged = true; + } + } + + /** + * Called by Location Services if the connection to the + * location client drops because of an error. + */ + @Override + public void onDisconnected() + { + if (mLocationClient == null) + return; + + // Display the connection status + Toast.makeText(this, "Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show(); + + // If the client is connected + if (mLocationClient.isConnected()) + { + /* + * Remove location updates for a listener. + * The current Activity is the listener, so + * the argument is "this". + */ + mLocationClient.removeLocationUpdates(this); + } + + location_service_running = false; + } + + /** + * Called by Location Services if the attempt to + * Location Services fails. + */ + @Override + public void onConnectionFailed(ConnectionResult connectionResult) + { + /* + * Google Play services can resolve some errors it detects. + * If the error has a resolution, try sending an Intent to + * start a Google Play services activity that can resolve + * error. + */ + if (connectionResult.hasResolution()) + { + try + { + // Start an Activity that tries to resolve the error + connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST); + } + catch (IntentSender.SendIntentException e) + { + // Thrown if Google Play services cancelled the original PendingIntent + e.printStackTrace(); + } + } + else + { + /* + * If no resolution is available, display a dialog to the + * user with the error. + */ + Log.e("Connection failed", "error code: " + connectionResult.getErrorCode()); + } + } + + /** + * Sets the update interval at which location-based updates + * should occur + */ + public void onLocationSetInterval(int update_interval_in_ms, int distance_interval) + { + // Use high accuracy + if (mLocationRequest == null) + return; + + mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + + if (update_interval_in_ms == 0) + mLocationRequest.setInterval(5 * 1000); // 5 seconds + else + mLocationRequest.setInterval(update_interval_in_ms); + + // Set the fastest update interval to 1 second + mLocationRequest.setFastestInterval(1000); + } + + /** + * Initializing methods for location based functionality. + */ + public void onLocationInit() + { + /* + * Create a new location client, using the enclosing class to + * handle callbacks. + */ + if (mLocationClient == null) + mLocationClient = new LocationClient(this, this, this); + + // Start with updates turned off + mUpdatesRequested = false; + + // Create the LocationRequest object + if (mLocationRequest == null) + mLocationRequest = LocationRequest.create(); + + onLocationSetInterval(0, 0); + } + + + /** + * Executed upon starting the {@link LocationClient}. + */ + public void onLocationStart() + { + if (mLocationClient == null) + return; + + mUpdatesRequested = true; + + // Connect the client. + mLocationClient.connect(); + } + + /** + * Free up location services resources. + */ + public void onLocationFree() + { + /* TODO/FIXME */ + } + + /** + * Executed upon stopping the location client. + * Does nothing if called when the client is not started. + */ + public void onLocationStop() + { + // Disconnecting the client invalidates it. + if (mLocationClient != null && mUpdatesRequested) + mLocationClient.disconnect(); + } + + /** + * Gets the latitude at the current location in degrees. + * + * @return the latitude at the current location. + */ + public double onLocationGetLatitude() + { + return mCurrentLocation.getLatitude(); + } + + /** + * Gets the longitude at the current location in degrees. + * + * @return the longitude at the current location. + */ + public double onLocationGetLongitude() + { + return mCurrentLocation.getLongitude(); + } + + /** + * Gets the horizontal accuracy of the current location + * in meters. (NOTE: There seems to be no vertical accuracy + * for a given location with the Android location API) + * + * @return the horizontal accuracy of the current position. + */ + public double onLocationGetHorizontalAccuracy() + { + return mCurrentLocation.getAccuracy(); + } + + /** + * Tells us whether the location listener callback has + * updated the current location since the last time + * we polled. + * + * @return true if location has changed, false if location has not changed. + */ + public boolean onLocationHasChanged() + { + boolean hasChanged = locationChanged; + + // Reset flag + if (hasChanged) + locationChanged = false; + + return hasChanged; + } + + // Define the callback method that receives location updates + @Override + public void onLocationChanged(Location location) + { + if (!location_service_running) + return; + + locationChanged = true; + mCurrentLocation = location; + + // Report to the UI that the location was updated + String msg = "Updated Location: " + location.getLatitude() + ", " + location.getLongitude(); + Log.i("RetroArch GPS", msg); + //Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onPause() + { + // Save the current setting for updates + SharedPreferences prefs = UserPreferences.getPreferences(this); + SharedPreferences.Editor edit = prefs.edit(); + edit.putBoolean("LOCATION_UPDATES_ON", mUpdatesRequested); + edit.apply(); + + super.onPause(); + } + + @Override + public void onResume() + { + SharedPreferences prefs = UserPreferences.getPreferences(this); + SharedPreferences.Editor edit = prefs.edit(); + + /* + * Get any previous setting for location updates + * Gets "false" if an error occurs + */ + if (prefs.contains("LOCATION_UPDATES_ON")) + { + mUpdatesRequested = prefs.getBoolean("LOCATION_UPDATES_ON", false); + if (mUpdatesRequested) + location_service_running = true; + } + else // Otherwise, turn off location updates + { + edit.putBoolean("LOCATION_UPDATES_ON", false); + edit.apply(); + location_service_running = false; + } + + super.onResume(); + } + + @Override + public void onStop() + { + onLocationStop(); + super.onStop(); + } +} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityPast.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityPast.java new file mode 100644 index 0000000000..4c11369ee9 --- /dev/null +++ b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityPast.java @@ -0,0 +1,7 @@ +package com.retroarch.browser.retroactivity; + +// For Android 2.3.x + +public final class RetroActivityPast extends RetroActivityCommon +{ +} diff --git a/pkg/android/phoenix64/version_increment.py b/pkg/android/phoenix64/version_increment.py new file mode 100644 index 0000000000..fbd58ff906 --- /dev/null +++ b/pkg/android/phoenix64/version_increment.py @@ -0,0 +1,20 @@ +#!/usr/bin/python +import time + + +from xml.dom.minidom import parse +dom1 = parse("AndroidManifest.xml") +oldVersion = dom1.documentElement.getAttribute("android:versionCode") +versionNumbers = oldVersion.split('.') + +versionName = dom1.documentElement.getAttribute("android:versionName") +versionName = versionName + "_GIT" + +versionNumbers[-1] = unicode(int(time.time())) +dom1.documentElement.setAttribute("android:versionCode", u'.'.join(versionNumbers)) +dom1.documentElement.setAttribute("android:versionName", versionName) + +with open("AndroidManifest.xml", 'wb') as f: + for line in dom1.toxml("utf-8"): + f.write(line) + From 9f60a6d17c8188f11651573fc360033bb2e29525 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 15 Aug 2018 16:10:52 -0400 Subject: [PATCH 021/182] fix Core Information not appearing after 73f2710 --- core_info.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core_info.c b/core_info.c index 18bcfeffec..15c5a0a32b 100644 --- a/core_info.c +++ b/core_info.c @@ -679,6 +679,9 @@ bool core_info_load(core_info_ctx_find_t *info) if (!info) return false; + if (!core_info_current) + core_info_init_current_core(); + core_info_get_current_core(&core_info); if (!core_info_curr_list) From 921e52e64f6940415d850589296fc9223c9b4671 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 00:05:09 +0200 Subject: [PATCH 022/182] Remove old leftover buggy Win32 driver --- gfx/common/win32_common.h | 2 - gfx/drivers/gl.c | 5 - ui/drivers/ui_win32.c | 455 -------------------------------------- 3 files changed, 462 deletions(-) diff --git a/gfx/common/win32_common.h b/gfx/common/win32_common.h index 7afe7d0dd3..f03940ce9d 100644 --- a/gfx/common/win32_common.h +++ b/gfx/common/win32_common.h @@ -63,8 +63,6 @@ void create_gdi_context(HWND hwnd, bool *quit); bool gdi_has_menu_frame(void); -void shader_dlg_params_reload(void); - bool win32_window_init(WNDCLASSEX *wndclass, bool fullscreen, const char *class_name); void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use, diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index 1008697366..d3e7dfd2a4 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -2200,11 +2200,6 @@ static bool gl_set_shader(void *data, /* Apparently need to set viewport for passes when we aren't using FBOs. */ gl_set_shader_viewports(gl); context_bind_hw_render(true); -#if defined(_WIN32) && !defined(_XBOX) - /* Shader dialog is disabled for now, until video_threaded issues are fixed. - shader_dlg_params_reload();*/ -#endif - #endif return true; diff --git a/ui/drivers/ui_win32.c b/ui/drivers/ui_win32.c index 2c771ef916..0fd3245901 100644 --- a/ui/drivers/ui_win32.c +++ b/ui/drivers/ui_win32.c @@ -55,451 +55,11 @@ #include "ui_win32.h" -#define SHADER_DLG_WIDTH 220 -#define SHADER_DLG_MIN_HEIGHT 200 -#define SHADER_DLG_MAX_HEIGHT 800 -#define SHADER_DLG_CTRL_MARGIN 8 -#define SHADER_DLG_CTRL_X 10 -#define SHADER_DLG_CHECKBOX_HEIGHT 15 -#define SHADER_DLG_SEPARATOR_HEIGHT 10 -#define SHADER_DLG_LABEL_HEIGHT 14 -#define SHADER_DLG_TRACKBAR_HEIGHT 22 -#define SHADER_DLG_TRACKBAR_LABEL_WIDTH 30 - -#define SHADER_DLG_CTRL_WIDTH (SHADER_DLG_WIDTH - 2 * SHADER_DLG_CTRL_X) -#define SHADER_DLG_TRACKBAR_WIDTH (SHADER_DLG_CTRL_WIDTH - SHADER_DLG_TRACKBAR_LABEL_WIDTH) - typedef struct ui_companion_win32 { void *empty; } ui_companion_win32_t; -#ifdef HAVE_SHADERPIPELINE -enum shader_param_ctrl_type -{ - SHADER_PARAM_CTRL_NONE = 0, - SHADER_PARAM_CTRL_CHECKBOX, - SHADER_PARAM_CTRL_TRACKBAR -}; - -enum -{ - SHADER_DLG_CHECKBOX_ONTOP_ID = GFX_MAX_PARAMETERS, - SHADER_DLG_CHECKBOX_BUTTON1_ID, - SHADER_DLG_CHECKBOX_BUTTON2_ID -}; - -typedef struct -{ - enum shader_param_ctrl_type type; - union - { - ui_window_win32_t checkbox; - struct - { - HWND hwnd; - HWND label_title; - HWND label_val; - } trackbar; - } elems; -} shader_param_ctrl_t; - -typedef struct -{ - ui_window_win32_t window; - ui_window_win32_t separator; - ui_window_win32_t on_top_checkbox; - shader_param_ctrl_t controls[GFX_MAX_PARAMETERS]; - int parameters_start_y; -} shader_dlg_t; - -static shader_dlg_t g_shader_dlg = {{0}}; - -static bool shader_dlg_refresh_trackbar_label(int index, - video_shader_ctx_t *shader_info) -{ - char val_buffer[32] = {0}; - - if (floorf(shader_info->data->parameters[index].current) - == shader_info->data->parameters[index].current) - snprintf(val_buffer, sizeof(val_buffer), "%.0f", - shader_info->data->parameters[index].current); - else - snprintf(val_buffer, sizeof(val_buffer), "%.2f", - shader_info->data->parameters[index].current); - - SendMessage(g_shader_dlg.controls[index].elems.trackbar.label_val, - WM_SETTEXT, 0, (LPARAM)val_buffer); - - return true; -} - -static void shader_dlg_params_refresh(void) -{ - int i; - - for (i = 0; i < GFX_MAX_PARAMETERS; i++) - { - shader_param_ctrl_t*control = &g_shader_dlg.controls[i]; - - if (control->type == SHADER_PARAM_CTRL_NONE) - break; - - switch (control->type) - { - case SHADER_PARAM_CTRL_CHECKBOX: - { - bool checked; - - video_shader_ctx_t shader_info; - video_shader_driver_get_current_shader(&shader_info); - - checked = shader_info.data ? - (shader_info.data->parameters[i].current == - shader_info.data->parameters[i].maximum) : false; - SendMessage(control->elems.checkbox.hwnd, BM_SETCHECK, checked, 0); - } - break; - case SHADER_PARAM_CTRL_TRACKBAR: - { - video_shader_ctx_t shader_info; - video_shader_driver_get_current_shader(&shader_info); - if (shader_info.data && !shader_dlg_refresh_trackbar_label(i, &shader_info)) - break; - - if (shader_info.data) - { - SendMessage(control->elems.trackbar.hwnd, - TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)0); - SendMessage(control->elems.trackbar.hwnd, - TBM_SETRANGEMAX, (WPARAM)TRUE, - (LPARAM)((shader_info.data->parameters[i].maximum - - shader_info.data->parameters[i].minimum) - / shader_info.data->parameters[i].step)); - SendMessage(control->elems.trackbar.hwnd, TBM_SETPOS, (WPARAM)TRUE, - (LPARAM)((shader_info.data->parameters[i].current - - shader_info.data->parameters[i].minimum) / - shader_info.data->parameters[i].step)); - } - } - break; - case SHADER_PARAM_CTRL_NONE: - default: - break; - } - } -} - -static void shader_dlg_params_clear(void) -{ - unsigned i; - - for (i = 0; i < GFX_MAX_PARAMETERS; i++) - { - shader_param_ctrl_t*control = &g_shader_dlg.controls[i]; - - if (!control || control->type == SHADER_PARAM_CTRL_NONE) - break; - - switch (control->type) - { - case SHADER_PARAM_CTRL_NONE: - break; - case SHADER_PARAM_CTRL_CHECKBOX: - { - const ui_window_t *window = ui_companion_driver_get_window_ptr(); - if (window) - window->destroy(&control->elems.checkbox); - } - break; - case SHADER_PARAM_CTRL_TRACKBAR: - DestroyWindow(control->elems.trackbar.label_title); - DestroyWindow(control->elems.trackbar.label_val); - DestroyWindow(control->elems.trackbar.hwnd); - break; - } - - control->type = SHADER_PARAM_CTRL_NONE; - } -} -#endif - -void shader_dlg_params_reload(void) -{ -#ifdef HAVE_SHADERPIPELINE - HFONT hFont; - RECT parent_rect; - int i, pos_x, pos_y; - video_shader_ctx_t shader_info; - const ui_window_t *window = NULL; - - shader_dlg_params_clear(); - - video_shader_driver_get_current_shader(&shader_info); - - if (!shader_info.data || shader_info.data->num_parameters > GFX_MAX_PARAMETERS) - return; - - window = ui_companion_driver_get_window_ptr(); - hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); - pos_y = g_shader_dlg.parameters_start_y; - pos_x = SHADER_DLG_CTRL_X; - - for (i = 0; i < (int)shader_info.data->num_parameters; i++) - { - shader_param_ctrl_t*control = &g_shader_dlg.controls[i]; - - if ((shader_info.data->parameters[i].minimum == 0.0) - && (shader_info.data->parameters[i].maximum - == (shader_info.data->parameters[i].minimum - + shader_info.data->parameters[i].step))) - { - if ((pos_y + SHADER_DLG_CHECKBOX_HEIGHT - + SHADER_DLG_CTRL_MARGIN + 20) - > SHADER_DLG_MAX_HEIGHT) - { - pos_y = g_shader_dlg.parameters_start_y; - pos_x += SHADER_DLG_WIDTH; - } - - control->type = SHADER_PARAM_CTRL_CHECKBOX; - control->elems.checkbox.hwnd = CreateWindowEx(0, "BUTTON", - shader_info.data->parameters[i].desc, - WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, pos_x, pos_y, - SHADER_DLG_CTRL_WIDTH, SHADER_DLG_CHECKBOX_HEIGHT, - g_shader_dlg.window.hwnd, (HMENU)(size_t)i, NULL, NULL); - SendMessage(control->elems.checkbox.hwnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); - pos_y += SHADER_DLG_CHECKBOX_HEIGHT + SHADER_DLG_CTRL_MARGIN; - } - else - { - if ((pos_y + SHADER_DLG_LABEL_HEIGHT + SHADER_DLG_TRACKBAR_HEIGHT + - SHADER_DLG_CTRL_MARGIN + 20) > SHADER_DLG_MAX_HEIGHT) - { - pos_y = g_shader_dlg.parameters_start_y; - pos_x += SHADER_DLG_WIDTH; - } - - control->type = SHADER_PARAM_CTRL_TRACKBAR; - control->elems.trackbar.label_title = CreateWindowEx(0, "STATIC", - shader_info.data->parameters[i].desc, - WS_CHILD | WS_VISIBLE | SS_LEFT, pos_x, pos_y, - SHADER_DLG_CTRL_WIDTH, SHADER_DLG_LABEL_HEIGHT, g_shader_dlg.window.hwnd, - (HMENU)(size_t)i, NULL, NULL); - SendMessage(control->elems.trackbar.label_title, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); - - pos_y += SHADER_DLG_LABEL_HEIGHT; - control->elems.trackbar.hwnd = CreateWindowEx(0, (LPCSTR)TRACKBAR_CLASS, "", - WS_CHILD | WS_VISIBLE | TBS_HORZ | TBS_NOTICKS, - pos_x + SHADER_DLG_TRACKBAR_LABEL_WIDTH, pos_y, - SHADER_DLG_TRACKBAR_WIDTH, SHADER_DLG_TRACKBAR_HEIGHT, - g_shader_dlg.window.hwnd, (HMENU)(size_t)i, NULL, NULL); - - control->elems.trackbar.label_val = CreateWindowEx(0, "STATIC", "", - WS_CHILD | WS_VISIBLE | SS_LEFT, pos_x, - pos_y, SHADER_DLG_TRACKBAR_LABEL_WIDTH, SHADER_DLG_LABEL_HEIGHT, - g_shader_dlg.window.hwnd, (HMENU)(size_t)i, NULL, NULL); - SendMessage(control->elems.trackbar.label_val, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); - - SendMessage(control->elems.trackbar.hwnd, TBM_SETBUDDY, (WPARAM)TRUE, - (LPARAM)control->elems.trackbar.label_val); - - pos_y += SHADER_DLG_TRACKBAR_HEIGHT + SHADER_DLG_CTRL_MARGIN; - - } - - } - - if (window && g_shader_dlg.separator.hwnd) - window->destroy(&g_shader_dlg.separator); - - g_shader_dlg.separator.hwnd = CreateWindowEx(0, "STATIC", "", - SS_ETCHEDHORZ | WS_VISIBLE | WS_CHILD, SHADER_DLG_CTRL_X, - g_shader_dlg.parameters_start_y - SHADER_DLG_CTRL_MARGIN - SHADER_DLG_SEPARATOR_HEIGHT / 2, - (pos_x - SHADER_DLG_CTRL_X) + SHADER_DLG_CTRL_WIDTH, - SHADER_DLG_SEPARATOR_HEIGHT / 2, - g_shader_dlg.window.hwnd, NULL, NULL, - NULL); - - shader_dlg_params_refresh(); - - GetWindowRect(g_shader_dlg.window.hwnd, &parent_rect); - SetWindowPos(g_shader_dlg.window.hwnd, NULL, 0, 0, - (pos_x - SHADER_DLG_CTRL_X) + SHADER_DLG_WIDTH, - (pos_x == SHADER_DLG_CTRL_X) ? pos_y + 30 : SHADER_DLG_MAX_HEIGHT, - SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); -#endif -} - -#ifdef HAVE_SHADERPIPELINE -static void shader_dlg_update_on_top_state(void) -{ - bool on_top = SendMessage(g_shader_dlg.on_top_checkbox.hwnd, - BM_GETCHECK, 0, 0) == BST_CHECKED; - - SetWindowPos(g_shader_dlg.window.hwnd, on_top - ? HWND_TOPMOST : HWND_NOTOPMOST , 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); -} - -static void shader_dlg_show(HWND parent_hwnd) -{ - const ui_window_t *window = ui_companion_driver_get_window_ptr(); - - if (!IsWindowVisible(g_shader_dlg.window.hwnd)) - { - if (parent_hwnd) - { - RECT parent_rect; - GetWindowRect(parent_hwnd, &parent_rect); - SetWindowPos(g_shader_dlg.window.hwnd, HWND_TOP, - parent_rect.right, parent_rect.top, - 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); - } - else - window->set_visible(&g_shader_dlg.window, true); - - shader_dlg_update_on_top_state(); - - shader_dlg_params_reload(); - - } - - window->set_focused(&g_shader_dlg.window); -} -#endif - -#if 0 -static LRESULT CALLBACK ShaderDlgWndProc(HWND hwnd, UINT message, - WPARAM wparam, LPARAM lparam) -{ - int i, pos; - const ui_window_t *window = ui_companion_driver_get_window_ptr(); - - switch (message) - { - case WM_CREATE: - break; - - case WM_CLOSE: - case WM_DESTROY: - case WM_QUIT: - if (window) - window->set_visible(&g_shader_dlg.window, false); - return 0; - - case WM_COMMAND: - i = LOWORD(wparam); - - if (i == SHADER_DLG_CHECKBOX_ONTOP_ID) - { - shader_dlg_update_on_top_state(); - break; - } - - if (i >= GFX_MAX_PARAMETERS) - break; - - if (g_shader_dlg.controls[i].type != SHADER_PARAM_CTRL_CHECKBOX) - break; - - { - video_shader_ctx_t shader_info; - video_shader_driver_get_current_shader(&shader_info); - - if (SendMessage(g_shader_dlg.controls[i].elems.checkbox.hwnd, - BM_GETCHECK, 0, 0) == BST_CHECKED) - shader_info.data->parameters[i].current = - shader_info.data->parameters[i].maximum; - else - shader_info.data->parameters[i].current = - shader_info.data->parameters[i].minimum; - } - break; - - case WM_HSCROLL: - { - video_shader_ctx_t shader_info; - video_shader_driver_get_current_shader(&shader_info); - i = GetWindowLong((HWND)lparam, GWL_ID); - - if (i >= GFX_MAX_PARAMETERS) - break; - - if (g_shader_dlg.controls[i].type != SHADER_PARAM_CTRL_TRACKBAR) - break; - - pos = (int)SendMessage(g_shader_dlg.controls[i].elems.trackbar.hwnd, TBM_GETPOS, 0, 0); - - { - - shader_info.data->parameters[i].current = - shader_info.data->parameters[i].minimum + pos * shader_info.data->parameters[i].step; - } - - if (shader_info.data) - shader_dlg_refresh_trackbar_label(i, &shader_info); - } - break; - - } - - return DefWindowProc(hwnd, message, wparam, lparam); -} - -static bool win32_shader_dlg_init(void) -{ - static bool inited = false; - int pos_y; - HFONT hFont; - - if (g_shader_dlg.window.hwnd) - return true; - - if (!inited) - { - WNDCLASSEX wc_shader_dlg = {0}; - INITCOMMONCONTROLSEX comm_ctrl_init = {0}; - - comm_ctrl_init.dwSize = sizeof(comm_ctrl_init); - comm_ctrl_init.dwICC = ICC_BAR_CLASSES; - - if (!InitCommonControlsEx(&comm_ctrl_init)) - return false; - - wc_shader_dlg.lpfnWndProc = ShaderDlgWndProc; - wc_shader_dlg.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - - if (!win32_window_init(&wc_shader_dlg, true, "Shader Dialog")) - return false; - - inited = true; - } - - hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); - - g_shader_dlg.window.hwnd = CreateWindowEx(0, "Shader Dialog", "Shader Parameters", - WS_POPUPWINDOW | WS_CAPTION, 100, 100, - SHADER_DLG_WIDTH, SHADER_DLG_MIN_HEIGHT, NULL, NULL, NULL, NULL); - - pos_y = SHADER_DLG_CTRL_MARGIN; - g_shader_dlg.on_top_checkbox.hwnd = CreateWindowEx(0, "BUTTON", "Always on Top", - BS_AUTOCHECKBOX | WS_VISIBLE | WS_CHILD, - SHADER_DLG_CTRL_X, pos_y, SHADER_DLG_CTRL_WIDTH, - SHADER_DLG_CHECKBOX_HEIGHT, g_shader_dlg.window.hwnd, - (HMENU)SHADER_DLG_CHECKBOX_ONTOP_ID, NULL, NULL); - pos_y += SHADER_DLG_CHECKBOX_HEIGHT + SHADER_DLG_CTRL_MARGIN; - - SendMessage(g_shader_dlg.on_top_checkbox.hwnd, - WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); - - pos_y += SHADER_DLG_SEPARATOR_HEIGHT + SHADER_DLG_CTRL_MARGIN; - - g_shader_dlg.parameters_start_y = pos_y; - return true; -} -#endif - bool win32_window_init(WNDCLASSEX *wndclass, bool fullscreen, const char *class_name) { @@ -520,16 +80,6 @@ bool win32_window_init(WNDCLASSEX *wndclass, if (!RegisterClassEx(wndclass)) return false; - /* This is non-NULL when we want a window for shader dialogs, - * therefore early return here */ - /* TODO/FIXME - this is ugly. Find a better way */ - if (class_name != NULL) - return true; - - /* Shader dialog is disabled for now, until - * video_threaded issues are fixed. - if (!win32_shader_dlg_init()) - RARCH_ERR("[WGL]: wgl_shader_dlg_init() failed.\n");*/ return true; } @@ -680,11 +230,6 @@ LRESULT win32_menu_loop(HWND owner, WPARAM wparam) case ID_M_FULL_SCREEN: cmd = CMD_EVENT_FULLSCREEN_TOGGLE; break; - case ID_M_SHADER_PARAMETERS: -#if !defined(_XBOX) && defined(HAVE_SHADERPIPELINE) - shader_dlg_show(owner); -#endif - break; case ID_M_MOUSE_GRAB: cmd = CMD_EVENT_GRAB_MOUSE_TOGGLE; break; From c663b0f87bf46b03b2daef482894c8a9d048d1e1 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 15 Aug 2018 21:40:39 -0400 Subject: [PATCH 023/182] Qt: make shader parameter window scrollable if there are too many items to show --- ui/drivers/qt/ui_qt_window.cpp | 45 +++++++++++++++++++++++++++++++--- ui/drivers/ui_qt.h | 3 +++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 6c2b63156a..394f7f7c45 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -212,6 +213,13 @@ ShaderParamsDialog::~ShaderParamsDialog() { } +void ShaderParamsDialog::resizeEvent(QResizeEvent *event) +{ + QDialog::resizeEvent(event); + + emit resized(event->size()); +} + void ShaderParamsDialog::closeEvent(QCloseEvent *event) { QDialog::closeEvent(event); @@ -1235,6 +1243,22 @@ void MainWindow::removeUpdateTempFiles() } } +void MainWindow::onShaderParamsDialogResized(QSize size) +{ + QVariant scrollAreaVariant = m_shaderParamsDialog->property("scrollArea"); + QScrollArea *scrollArea = NULL; + + if (!scrollAreaVariant.isValid()) + return; + + scrollArea = scrollAreaVariant.value(); + + if (!scrollArea) + return; + + scrollArea->resize(size); +} + void MainWindow::onShaderParamsClicked() { video_shader_ctx_t shader_info; @@ -1242,6 +1266,9 @@ void MainWindow::onShaderParamsClicked() int last_pass = -1; QFormLayout *last_form = NULL; QGroupBox *last_group = NULL; + QScrollArea *scrollArea = NULL; + QWidget *widget = NULL; + QVBoxLayout *layout = NULL; video_shader_driver_get_current_shader(&shader_info); @@ -1253,17 +1280,27 @@ void MainWindow::onShaderParamsClicked() delete m_shaderParamsDialog; m_shaderParamsDialog = new ShaderParamsDialog(); - m_shaderParamsDialog->setLayout(new QVBoxLayout()); + //m_shaderParamsDialog->setLayout(new QVBoxLayout()); m_shaderParamsDialog->setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS)); + layout = new QVBoxLayout(); + widget = new QWidget(); + widget->setLayout(layout); + scrollArea = new QScrollArea(m_shaderParamsDialog); + scrollArea->setWidgetResizable(true); + scrollArea->setWidget(widget); + + m_shaderParamsDialog->setProperty("scrollArea", QVariant::fromValue(scrollArea)); + connect(m_shaderParamsDialog, SIGNAL(closed()), m_shaderParamsDialog, SLOT(deleteLater())); + connect(m_shaderParamsDialog, SIGNAL(resized(QSize)), this, SLOT(onShaderParamsDialogResized(QSize))); if (shader_info.data->num_parameters == 0) { QLabel *label = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS), m_shaderParamsDialog); label->setAlignment(Qt::AlignCenter); - m_shaderParamsDialog->layout()->addWidget(label); + layout->addWidget(label); } else { @@ -1284,7 +1321,7 @@ void MainWindow::onShaderParamsClicked() groupBox = new QGroupBox(shaderBasename); groupBox->setLayout(form); - m_shaderParamsDialog->layout()->addWidget(groupBox); + layout->addWidget(groupBox); last_form = form; last_pass = param->pass; @@ -1354,7 +1391,7 @@ void MainWindow::onShaderParamsClicked() } } - m_shaderParamsDialog->layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); + layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); } m_shaderParamsDialog->resize(720, 480); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 98519dcdf8..8823d243a6 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -258,8 +258,10 @@ public: ~ShaderParamsDialog(); signals: void closed(); + void resized(QSize size); protected: void closeEvent(QCloseEvent *event); + void resizeEvent(QResizeEvent *event); }; class CoreInfoLabel : public QLabel @@ -462,6 +464,7 @@ private slots: void onShaderParamSliderValueChanged(int value); void onShaderParamSpinBoxValueChanged(int value); void onShaderParamDoubleSpinBoxValueChanged(double value); + void onShaderParamsDialogResized(QSize size); int onExtractArchive(QString path); private: From c74c3c953605bc34ba25547828b0221cd0b045fd Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 15 Aug 2018 21:41:44 -0400 Subject: [PATCH 024/182] Qt: set object names --- ui/drivers/qt/ui_qt_window.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 394f7f7c45..74efb56118 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -1280,15 +1280,17 @@ void MainWindow::onShaderParamsClicked() delete m_shaderParamsDialog; m_shaderParamsDialog = new ShaderParamsDialog(); - //m_shaderParamsDialog->setLayout(new QVBoxLayout()); m_shaderParamsDialog->setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS)); + m_shaderParamsDialog->setObjectName("shaderParamsDialog"); layout = new QVBoxLayout(); widget = new QWidget(); widget->setLayout(layout); + widget->setObjectName("shaderParamsWidget"); scrollArea = new QScrollArea(m_shaderParamsDialog); scrollArea->setWidgetResizable(true); scrollArea->setWidget(widget); + scrollArea->setObjectName("shaderParamsScrollArea"); m_shaderParamsDialog->setProperty("scrollArea", QVariant::fromValue(scrollArea)); From e2e43e6adee22e5d14362088ba21f45ab7f381b8 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 09:50:37 +0200 Subject: [PATCH 025/182] Update - make sure non-HAVE_MENU targets can compile --- command.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/command.c b/command.c index 4ccc4f5f6f..7b0dcc878c 100644 --- a/command.c +++ b/command.c @@ -230,9 +230,11 @@ bool command_set_shader(const char *arg) { char msg[256]; bool is_preset = false; - struct video_shader *shader = menu_shader_get(); enum rarch_shader_type type = video_shader_get_type_from_ext( path_get_extension(arg), &is_preset); +#ifdef HAVE_MENU + struct video_shader *shader = menu_shader_get(); +#endif if (type == RARCH_SHADER_NONE) return false; @@ -244,7 +246,11 @@ bool command_set_shader(const char *arg) arg); retroarch_set_shader_preset(arg); +#ifdef HAVE_MENU return menu_shader_manager_set_preset(shader, type, arg); +#else + return true; +#endif } static bool command_version(const char* arg) From 6266065384de5952d8ae3c7ec0f24fe15b56abe5 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 09:59:51 +0200 Subject: [PATCH 026/182] Fix more code when compiling without menu support --- command.c | 15 ++++++++------- gfx/drivers/gl.c | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/command.c b/command.c index 7b0dcc878c..0c128985f4 100644 --- a/command.c +++ b/command.c @@ -255,13 +255,14 @@ bool command_set_shader(const char *arg) static bool command_version(const char* arg) { - char reply[256] = {0}; + char reply[256] = {0}; - sprintf(reply, "%s\n", PACKAGE_VERSION); + sprintf(reply, "%s\n", PACKAGE_VERSION); #if defined(HAVE_CHEEVOS) && (defined(HAVE_STDIN_CMD) || defined(HAVE_NETWORK_CMD) && defined(HAVE_NETWORKING)) - command_reply(reply, strlen(reply)); + command_reply(reply, strlen(reply)); #endif - return true; + + return true; } #if defined(HAVE_COMMAND) && defined(HAVE_CHEEVOS) @@ -556,10 +557,10 @@ bool command_network_send(const char *cmd_) } free(command); - return ret; -#else - return false; + if (ret) + return true; #endif + return false; } #ifdef HAVE_STDIN_CMD diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index d3e7dfd2a4..f47cc488c4 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -832,7 +832,6 @@ static void gl_set_osd_msg(void *data, font_driver_render_msg(video_info, font, msg, (const struct font_params *)params); } -#if defined(HAVE_MENU) static void gl_show_mouse(void *data, bool state) { video_context_driver_show_mouse(&state); @@ -847,6 +846,7 @@ static struct video_shader *gl_get_current_shader(void *data) return shader_info.data; } +#if defined(HAVE_MENU) static INLINE void gl_draw_texture(gl_t *gl, video_frame_info_t *video_info) { video_shader_ctx_coords_t coords; From c12baad087aa21af809d660250f85956fbb4ce11 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 10:12:17 +0200 Subject: [PATCH 027/182] Fixup compat_snprintf.c for MSVC 2008 --- libretro-common/compat/compat_snprintf.c | 14 +++++++------- libretro-common/include/compat/msvc.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libretro-common/compat/compat_snprintf.c b/libretro-common/compat/compat_snprintf.c index f67301ade2..7011644280 100644 --- a/libretro-common/compat/compat_snprintf.c +++ b/libretro-common/compat/compat_snprintf.c @@ -23,10 +23,7 @@ /* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */ #ifdef _MSC_VER -#include -#if _MSC_VER >= 1800 -#include /* added for _vsnprintf_s and _vscprintf on VS2015 and VS2017 */ -#endif +#include #include #if _MSC_VER < 1800 @@ -52,13 +49,16 @@ static int c89_vscprintf_retro__(const char *format, va_list pargs) int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap) { int count = -1; - + if (size != 0) + { #if (_MSC_VER <= 1310) - count = _vsnprintf(outBuf, size - 1, format, ap); + count = _vsnprintf(outBuf, size - 1, format, ap); #else - count = _vsnprintf_s(outBuf, size, size - 1, format, ap); + count = _vsnprintf_s(outBuf, size, size - 1, format, ap); #endif + } + if (count == -1) count = _vscprintf(format, ap); diff --git a/libretro-common/include/compat/msvc.h b/libretro-common/include/compat/msvc.h index 822c97339a..0a25cd9370 100644 --- a/libretro-common/include/compat/msvc.h +++ b/libretro-common/include/compat/msvc.h @@ -39,8 +39,8 @@ extern "C" { int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...); #endif -/* Pre-MSVC 2010 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */ -#if _MSC_VER < 1600 +/* Pre-MSVC 2008 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */ +#if _MSC_VER < 1500 #include #include #ifndef vsnprintf From 75a388cd67f2c5f58e49aadaa20d5f89ca436e5a Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 10:14:42 +0200 Subject: [PATCH 028/182] Use strlcpy instead of strncpy in slang_process.cpp --- gfx/drivers_shader/slang_process.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gfx/drivers_shader/slang_process.cpp b/gfx/drivers_shader/slang_process.cpp index d1a113c3af..a8a6db588b 100644 --- a/gfx/drivers_shader/slang_process.cpp +++ b/gfx/drivers_shader/slang_process.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -200,7 +201,7 @@ static bool slang_process_reflection( string uniform_id = get_semantic_name( sl_reflection, (slang_semantic)semantic, 0); - strncpy(uniform.id, uniform_id.c_str(), sizeof(uniform.id)); + strlcpy(uniform.id, uniform_id.c_str(), sizeof(uniform.id)); if (src.push_constant) { @@ -226,7 +227,7 @@ static bool slang_process_reflection( string uniform_id = get_semantic_name( sl_reflection, SLANG_SEMANTIC_FLOAT_PARAMETER, i); - strncpy(uniform.id, uniform_id.c_str(), sizeof(uniform.id)); + strlcpy(uniform.id, uniform_id.c_str(), sizeof(uniform.id)); if (src.push_constant) { @@ -272,7 +273,7 @@ static bool slang_process_reflection( string id = get_semantic_name( sl_reflection, (slang_texture_semantic)semantic, index); - strncpy(texture.id, id.c_str(), sizeof(texture.id)); + strlcpy(texture.id, id.c_str(), sizeof(texture.id)); textures.push_back(texture); @@ -297,7 +298,7 @@ static bool slang_process_reflection( sl_reflection, (slang_texture_semantic)semantic, index); - strncpy(uniform.id, uniform_id.c_str(), sizeof(uniform.id)); + strlcpy(uniform.id, uniform_id.c_str(), sizeof(uniform.id)); if (src.push_constant) { @@ -361,7 +362,7 @@ bool slang_process( return false; if (!*pass.alias && !output.meta.name.empty()) - strncpy(pass.alias, output.meta.name.c_str(), sizeof(pass.alias) - 1); + strlcpy(pass.alias, output.meta.name.c_str(), sizeof(pass.alias) - 1); out->format = output.meta.rt_format; From ba676239619581076460d387fbec33cd94bb05de Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 10:15:51 +0200 Subject: [PATCH 029/182] (Menu) change strncpy to strlcpy --- menu/cbs/menu_cbs_ok.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 9de84c207b..51c2a5c6b2 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -993,7 +993,7 @@ static bool menu_content_playlist_load(playlist_t *playlist, size_t idx) path_check = (char *) calloc(strlen(path_tolower) + 1, sizeof(char)); - strncpy(path_check, path, strlen(path_tolower)); + strlcpy(path_check, path, strlen(path_tolower)); valid_path = path_is_valid(path_check); From 3fb039f9f0fdfaad6f025e936f671b9a28387408 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 10:18:00 +0200 Subject: [PATCH 030/182] Update menu_display_metal.m --- menu/drivers_display/menu_display_metal.m | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/menu/drivers_display/menu_display_metal.m b/menu/drivers_display/menu_display_metal.m index 7ff5a5bfa7..d15e4ed98e 100644 --- a/menu/drivers_display/menu_display_metal.m +++ b/menu/drivers_display/menu_display_metal.m @@ -1,9 +1,17 @@ -// -// menu_display_metal.m -// RetroArch_Metal -// -// Created by Stuart Carnie on 5/25/18. -// +/* RetroArch - A frontend for libretro. + * Copyright (C) 2018 - Stuart Carnie + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ #include From de8c98fdef3cf6786c4f7f0f2534b6027a0388bd Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 10:18:56 +0200 Subject: [PATCH 031/182] Remove ID_M_SHADER_PARAMETERS --- ui/drivers/ui_win32_resource.h | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/drivers/ui_win32_resource.h b/ui/drivers/ui_win32_resource.h index 4a4e79259a..e7090d701e 100644 --- a/ui/drivers/ui_win32_resource.h +++ b/ui/drivers/ui_win32_resource.h @@ -29,4 +29,3 @@ #define ID_M_STATE_INDEX_AUTO 40024 #define ID_M_TAKE_SCREENSHOT 40025 #define ID_M_MUTE_TOGGLE 40026 -#define ID_M_SHADER_PARAMETERS 40027 From 3f4cd71aa355b33ac5678c084e2db01dbf383259 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 10:42:26 +0200 Subject: [PATCH 032/182] Cleanups --- ui/drivers/ui_win32.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ui/drivers/ui_win32.c b/ui/drivers/ui_win32.c index 0fd3245901..aa3b075359 100644 --- a/ui/drivers/ui_win32.c +++ b/ui/drivers/ui_win32.c @@ -24,9 +24,6 @@ #pragma comment( lib, "comctl32" ) #endif -#define TITLE_MAX PATH_MAX -#define FULLPATH_MAX 32768 - #define IDI_ICON 1 #ifndef _WIN32_WINNT @@ -104,8 +101,8 @@ static bool win32_browser( * path/name of any file the user may select. * FIXME: We should really handle the * error case when this isn't big enough. */ - char new_title[TITLE_MAX]; - char new_file[FULLPATH_MAX]; + char new_title[PATH_MAX]; + char new_file[32768]; new_title[0] = '\0'; new_file[0] = '\0'; From fd532414f0d2e7c68db93d80d169f2589c9c35be Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 10:57:33 +0200 Subject: [PATCH 033/182] (DSound) Add fallback when we are not building with HAVE_THREADS support --- audio/drivers/dsound.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/audio/drivers/dsound.c b/audio/drivers/dsound.c index d6a89db3c0..396ff8a332 100644 --- a/audio/drivers/dsound.c +++ b/audio/drivers/dsound.c @@ -32,7 +32,9 @@ #include #include #include +#ifdef HAVE_THREADS #include +#endif #include #include "../audio_driver.h" @@ -59,7 +61,11 @@ typedef struct dsound CRITICAL_SECTION crit; HANDLE event; +#ifdef HAVE_THREADS sthread_t *thread; +#else + HANDLE thread; +#endif unsigned buffer_size; @@ -137,7 +143,11 @@ static INLINE void release_region(dsound_t *ds, const struct audio_lock *region) region->size1, region->chunk2, region->size2); } +#ifdef HAVE_THREADS static void dsound_thread(void *data) +#else +static DWORD CALLBACK dsound_thread(PVOID data) +#endif { DWORD write_ptr; dsound_t *ds = (dsound_t*)data; @@ -219,7 +229,13 @@ static void dsound_stop_thread(dsound_t *ds) ds->thread_alive = false; +#ifdef HAVE_THREADS sthread_join(ds->thread); +#else + WaitForSingleObject(ds->thread, INFINITE); + CloseHandle(ds->thread); +#endif + ds->thread = NULL; } @@ -228,7 +244,12 @@ static bool dsound_start_thread(dsound_t *ds) if (!ds->thread) { ds->thread_alive = true; - ds->thread = sthread_create(dsound_thread, ds); + +#ifdef HAVE_THREADS + ds->thread = sthread_create(dsound_thread, ds); +#else + ds->thread = CreateThread(NULL, 0, dsound_thread, ds, 0, NULL); +#endif if (!ds->thread) return false; } @@ -261,7 +282,12 @@ static void dsound_free(void *data) if (ds->thread) { ds->thread_alive = false; +#ifdef HAVE_THREADS sthread_join(ds->thread); +#else + WaitForSingleObject(ds->thread, INFINITE); + CloseHandle(ds->thread); +#endif } DeleteCriticalSection(&ds->crit); From a8826c766b8c40589eddf5d85cac44942b3128bd Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 11:06:22 +0200 Subject: [PATCH 034/182] (MSVC2008) Update solution --- pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj b/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj index ced820b582..1373591a8a 100644 --- a/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj +++ b/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj @@ -286,6 +286,7 @@ SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" + EntryPointSymbol="mainCRTStartup" TargetMachine="1" /> Date: Thu, 16 Aug 2018 11:18:56 +0200 Subject: [PATCH 035/182] Update MSVC 2008 solution --- pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj b/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj index 1373591a8a..a9cdc74eb9 100644 --- a/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj +++ b/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj @@ -42,7 +42,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(SolutionDir)\..\..\libretro-common\include";"$(SolutionDir)\..\..\libretro-common\include\compat\msvc";"$(SolutionDir)\..\..\deps"" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_GRIFFIN;RARCH_INTERNAL;HAVE_D3D;HAVE_D3D9;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DINPUT;HAVE_XINPUT;HAVE_DYLIB;HAVE_DYNAMIC;__STDC_CONSTANT_MACROS" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_CHEEVOS;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_UPDATE_ASSETS;HAVE_RUNAHEAD;HAVE_D3D;HAVE_D3D9;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DINPUT;HAVE_XINPUT;HAVE_DYLIB;HAVE_DYNAMIC;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT;__STDC_CONSTANT_MACROS" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -61,6 +61,7 @@ /> Date: Thu, 16 Aug 2018 11:44:51 +0200 Subject: [PATCH 036/182] Update MSVC 2008 solution --- pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj b/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj index a9cdc74eb9..c7c4251f6b 100644 --- a/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj +++ b/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj @@ -41,8 +41,8 @@ Date: Thu, 16 Aug 2018 11:50:51 +0200 Subject: [PATCH 037/182] Update MSVC2008 --- pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj b/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj index c7c4251f6b..c6e5589e48 100644 --- a/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj +++ b/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj @@ -42,7 +42,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(SolutionDir)\..\..\libretro-common\include";"$(SolutionDir)\..\..\libretro-common\include\compat\msvc";"$(SolutionDir)\..\..\deps";"$(SolutionDir)\..\..\gfx\includev"" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_CHEEVOS;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_UPDATE_ASSETS;HAVE_RUNAHEAD;HAVE_D3D;HAVE_D3D9;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_GLSL;HAVE_DINPUT;HAVE_XINPUT;HAVE_DYLIB;HAVE_DYNAMIC;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT;__STDC_CONSTANT_MACROS" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_CHEEVOS;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_UPDATE_ASSETS;HAVE_RUNAHEAD;HAVE_D3D;HAVE_D3D9;HAVE_D3DX;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_GLSL;HAVE_DINPUT;HAVE_XINPUT;HAVE_DYLIB;HAVE_DYNAMIC;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT;__STDC_CONSTANT_MACROS" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -118,7 +118,7 @@ Optimization="2" EnableIntrinsicFunctions="true" AdditionalIncludeDirectories=""$(SolutionDir)\..\..\libretro-common\include";"$(SolutionDir)\..\..\libretro-common\include\compat\msvc";"$(SolutionDir)\..\..\deps";"$(SolutionDir)\..\..\gfx\include";"$(DXSDK_DIR)Include"" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_CHEEVOS;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_UPDATE_ASSETS;HAVE_RUNAHEAD;HAVE_D3D;HAVE_D3D9;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_GLSL;HAVE_DINPUT;HAVE_XINPUT;HAVE_DYLIB;HAVE_DYNAMIC;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT;__STDC_CONSTANT_MACROS" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_CHEEVOS;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_UPDATE_ASSETS;HAVE_RUNAHEAD;HAVE_D3D;HAVE_D3D9;HAVE_D3DX;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_GLSL;HAVE_DINPUT;HAVE_XINPUT;HAVE_DYLIB;HAVE_DYNAMIC;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT;__STDC_CONSTANT_MACROS" RuntimeLibrary="2" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" From 6001c7f03090facad28851044ba84c922ffc6a9c Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 11:53:46 +0200 Subject: [PATCH 038/182] (MSVC 2008) Add HAVE_OVERLAY --- pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj b/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj index c6e5589e48..c456b38284 100644 --- a/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj +++ b/pkg/msvc/msvc-2008/RetroArch-msvc2008.vcproj @@ -42,7 +42,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(SolutionDir)\..\..\libretro-common\include";"$(SolutionDir)\..\..\libretro-common\include\compat\msvc";"$(SolutionDir)\..\..\deps";"$(SolutionDir)\..\..\gfx\includev"" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_CHEEVOS;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_UPDATE_ASSETS;HAVE_RUNAHEAD;HAVE_D3D;HAVE_D3D9;HAVE_D3DX;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_GLSL;HAVE_DINPUT;HAVE_XINPUT;HAVE_DYLIB;HAVE_DYNAMIC;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT;__STDC_CONSTANT_MACROS" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_CHEEVOS;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_UPDATE_ASSETS;HAVE_RUNAHEAD;HAVE_D3D;HAVE_D3D9;HAVE_D3DX;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_GLSL;HAVE_OVERLAY;HAVE_DINPUT;HAVE_XINPUT;HAVE_DYLIB;HAVE_DYNAMIC;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT;__STDC_CONSTANT_MACROS" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -118,7 +118,7 @@ Optimization="2" EnableIntrinsicFunctions="true" AdditionalIncludeDirectories=""$(SolutionDir)\..\..\libretro-common\include";"$(SolutionDir)\..\..\libretro-common\include\compat\msvc";"$(SolutionDir)\..\..\deps";"$(SolutionDir)\..\..\gfx\include";"$(DXSDK_DIR)Include"" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_CHEEVOS;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_UPDATE_ASSETS;HAVE_RUNAHEAD;HAVE_D3D;HAVE_D3D9;HAVE_D3DX;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_GLSL;HAVE_DINPUT;HAVE_XINPUT;HAVE_DYLIB;HAVE_DYNAMIC;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT;__STDC_CONSTANT_MACROS" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_GRIFFIN;HAVE_LANGEXTRA;HAVE_CHEEVOS;HAVE_ZLIB;HAVE_RPNG;HAVE_RJPEG;HAVE_RBMP;HAVE_RTGA;HAVE_IMAGEVIEWER;HAVE_XMB;HAVE_SHADERPIPELINE;WANT_ZLIB;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_UPDATE_ASSETS;HAVE_RUNAHEAD;HAVE_D3D;HAVE_D3D9;HAVE_D3DX;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_GLSL;HAVE_OVERLAY;HAVE_DINPUT;HAVE_XINPUT;HAVE_DYLIB;HAVE_DYNAMIC;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_MENU;HAVE_7ZIP;HAVE_MATERIALUI;HAVE_LIBRETRODB;HAVE_STB_FONT;__STDC_CONSTANT_MACROS" RuntimeLibrary="2" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" From f750229693abd56a78feab347def702098f50681 Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Thu, 16 Aug 2018 13:12:34 +0200 Subject: [PATCH 039/182] Desktop UI dark theme updates --- ui/drivers/qt/ui_qt_themes.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/ui/drivers/qt/ui_qt_themes.h b/ui/drivers/qt/ui_qt_themes.h index d8e6baeb98..9f22672956 100644 --- a/ui/drivers/qt/ui_qt_themes.h +++ b/ui/drivers/qt/ui_qt_themes.h @@ -31,6 +31,35 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral("" " border-right:1px solid rgba(125,125,125,50%);\n" " border-bottom:1px solid rgba(25,25,25,75%);\n" "}\n" + "QTextEdit, LogTextEdit {\n" + " background-color:rgb(25,25,25);\n" + "}\n" + "QSpinBox, QCheckBox {\n" + " background-color:rgb(25,25,25);\n" + "}\n" + "QCheckBox:checked, QCheckBox:unchecked {\n" + " background-color:rgb(53,53,53);\n" + "}\n" + "QDialog#shaderParamsDialog {\n" + " background-color:rgb(25,25,25);\n" + "}\n" + "QDialog#shaderParamsDialog QGroupBox, QDialog#shaderParamsDialog QGroupBox QLabel,\n" + "QDialog#shaderParamsDialog QGroupBox QSlider, QDialog#shaderParamsDialog QGroupBox QCheckBox:checked,\n" + "QDialog#shaderParamsDialog QGroupBox QCheckBox:unchecked {\n" + " background-color:rgb(53,53,53);\n" + "}\n" + "QDialog#shaderParamsDialog QGroupBox {\n" + " border-top-left-radius: 0px;\n" + "}\n" + "QDialog#shaderParamsDialog QGroupBox::title {\n" + " margin-left:0px;\n" + " min-height:28px;\n" + " padding:4px 10px;\n" + " background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgb(53,53,53),stop:1 rgba(125,125,125,127));\n" + " border:1px solid rgba(25,25,25,75);\n" + " border-top:1px solid rgba(175,175,175,50%);\n" + " border-bottom: none transparent;\n" + "}\n" "QToolTip {\n" " color:white;\n" " background-color:rgb(53,53,53);\n" From 18a6467d4fc49d0264f4efc048994e36c8da85cd Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 16 Aug 2018 08:42:40 -0400 Subject: [PATCH 040/182] Qt: update success is not an error --- ui/drivers/qt/ui_qt_window.cpp | 8 +++++++- ui/drivers/ui_qt.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 74efb56118..2f09752689 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -1181,6 +1181,7 @@ MainWindow::MainWindow(QWidget *parent) : /* these are always queued */ connect(this, SIGNAL(showErrorMessageDeferred(QString)), this, SLOT(onShowErrorMessage(QString)), Qt::QueuedConnection); + connect(this, SIGNAL(showInfoMessageDeferred(QString)), this, SLOT(onShowInfoMessage(QString)), Qt::QueuedConnection); connect(this, SIGNAL(extractArchiveDeferred(QString)), this, SLOT(onExtractArchive(QString)), Qt::QueuedConnection); m_timer->start(TIMER_MSEC); @@ -5131,6 +5132,11 @@ void MainWindow::onShowErrorMessage(QString msg) showMessageBox(msg, MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); } +void MainWindow::onShowInfoMessage(QString msg) +{ + showMessageBox(msg, MainWindow::MSGBOX_TYPE_INFO, Qt::ApplicationModal, false); +} + void MainWindow::onRetroArchUpdateDownloadFinished() { QNetworkReply *reply = m_updateReply.data(); @@ -5231,7 +5237,7 @@ void MainWindow::onUpdateRetroArchFinished(bool success) RARCH_LOG("[Qt]: RetroArch update finished successfully.\n"); - emit showErrorMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED)); + emit showInfoMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED)); } int MainWindow::onExtractArchive(QString path) diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 8823d243a6..f1a1bd03b6 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -381,6 +381,7 @@ signals: void gotReloadPlaylists(); void gotReloadShaderParams(); void showErrorMessageDeferred(QString msg); + void showInfoMessageDeferred(QString msg); void extractArchiveDeferred(QString path); public slots: @@ -459,6 +460,7 @@ private slots: void onUpdateDownloadReadyRead(); void onUpdateDownloadCanceled(); void onShowErrorMessage(QString msg); + void onShowInfoMessage(QString msg); void onContributorsClicked(); void onShaderParamCheckBoxClicked(); void onShaderParamSliderValueChanged(int value); From 34e48bcbc908f4edca4ed80f4790506fe621fb0c Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 16 Aug 2018 09:29:32 -0400 Subject: [PATCH 041/182] Update AUTHORS.h --- AUTHORS.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AUTHORS.h b/AUTHORS.h index 7ef8548e1f..a7f3298fb4 100644 --- a/AUTHORS.h +++ b/AUTHORS.h @@ -92,6 +92,7 @@ Fabio Ritrovato (Sephiroth87) Fayne Aldan (FayneAldan) FIX94 Flame Sage (chris062689) +flyinghead Francisco José García García (frangarcj) GameDragon2k Garrett Brown (garbear) @@ -124,6 +125,7 @@ Jay McCarthy (jeapostrophe) Jean-André Santoni (kivutar) Jean-Paul Mari (djipi) Jean-Sébastien Guay (Skylark13) +Jesse Bryan (winneon) Joel (joel16) Joerg Sonnenberger (jsonn) Johannes Schickel (lordhoto) @@ -260,6 +262,7 @@ Vladimir Panteleev (CyberShadow) Víctor "IlDucci" (IlDucci) Wang Vincent (susemm) webgeek1234 +Wiktor Strzębała (wiktorek140) xhp-creations Yarsan Hoessain (hyarsan) Yongwoon Cho (ssangkong) From f8521a5580a9e68159025722c42c9b63ed5f06bf Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 16 Aug 2018 10:20:37 -0400 Subject: [PATCH 042/182] Qt: use string literal for themes --- ui/drivers/qt/ui_qt_themes.h | 860 +++++++++++++++++------------------ 1 file changed, 430 insertions(+), 430 deletions(-) diff --git a/ui/drivers/qt/ui_qt_themes.h b/ui/drivers/qt/ui_qt_themes.h index 9f22672956..1844930c45 100644 --- a/ui/drivers/qt/ui_qt_themes.h +++ b/ui/drivers/qt/ui_qt_themes.h @@ -1,434 +1,434 @@ #include /* %1 is a placeholder for palette(highlight) or the equivalent chosen by the user */ -static const QString qt_theme_default_stylesheet = QStringLiteral("" - "QPushButton[flat=\"true\"] {\n" - " min-height:20px;\n" - " min-width:80px;\n" - " padding:1px 3px 1px 3px;\n" - " background-color: transparent;\n" - " border: 1px solid #ddd;\n" - "}\n" - "ThumbnailWidget#thumbnailWidget, ThumbnailLabel#thumbnailGridLabel, QLabel#thumbnailQLabel {\n" - " background-color:#d4d4d4;\n" - "}\n" - "ThumbnailWidget#thumbnailWidgetSelected {\n" - " background-color:#d4d4d4;\n" - " border:3px solid %1;\n" - "}\n" -); +static const QString qt_theme_default_stylesheet = QStringLiteral(R"( + QPushButton[flat="true"] { + min-height:20px; + min-width:80px; + padding:1px 3px 1px 3px; + background-color: transparent; + border: 1px solid #ddd; + } + ThumbnailWidget#thumbnailWidget, ThumbnailLabel#thumbnailGridLabel, QLabel#thumbnailQLabel { + background-color:#d4d4d4; + } + ThumbnailWidget#thumbnailWidgetSelected { + background-color:#d4d4d4; + border:3px solid %1; + } +)"); -static const QString qt_theme_dark_stylesheet = QStringLiteral("" - "QWidget {\n" - " color:white;\n" - " background-color:rgb(53,53,53);\n" - " selection-background-color:%1;\n" - "}\n" - "QWidget#playlistWidget, QWidget#browserWidget, QWidget#tableWidget, QWidget#logWidget {\n" - " background-color:rgb(66,66,66);\n" - " border-top:1px solid rgba(175,175,175,50%);\n" - " border-left:1px solid rgba(125,125,125,50%);\n" - " border-right:1px solid rgba(125,125,125,50%);\n" - " border-bottom:1px solid rgba(25,25,25,75%);\n" - "}\n" - "QTextEdit, LogTextEdit {\n" - " background-color:rgb(25,25,25);\n" - "}\n" - "QSpinBox, QCheckBox {\n" - " background-color:rgb(25,25,25);\n" - "}\n" - "QCheckBox:checked, QCheckBox:unchecked {\n" - " background-color:rgb(53,53,53);\n" - "}\n" - "QDialog#shaderParamsDialog {\n" - " background-color:rgb(25,25,25);\n" - "}\n" - "QDialog#shaderParamsDialog QGroupBox, QDialog#shaderParamsDialog QGroupBox QLabel,\n" - "QDialog#shaderParamsDialog QGroupBox QSlider, QDialog#shaderParamsDialog QGroupBox QCheckBox:checked,\n" - "QDialog#shaderParamsDialog QGroupBox QCheckBox:unchecked {\n" - " background-color:rgb(53,53,53);\n" - "}\n" - "QDialog#shaderParamsDialog QGroupBox {\n" - " border-top-left-radius: 0px;\n" - "}\n" - "QDialog#shaderParamsDialog QGroupBox::title {\n" - " margin-left:0px;\n" - " min-height:28px;\n" - " padding:4px 10px;\n" - " background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgb(53,53,53),stop:1 rgba(125,125,125,127));\n" - " border:1px solid rgba(25,25,25,75);\n" - " border-top:1px solid rgba(175,175,175,50%);\n" - " border-bottom: none transparent;\n" - "}\n" - "QToolTip {\n" - " color:white;\n" - " background-color:rgb(53,53,53);\n" - " border:1px solid rgb(80,80,80);\n" - " border-radius:4px;\n" - "}\n" - "QMenuBar {\n" - " background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - " border-bottom:2px solid rgba(25,25,25,75);\n" - "}\n" - "QMenuBar::item {\n" - " spacing:2px;\n" - " padding:3px 4px;\n" - " background-color:transparent;\n" - "}\n" - "QMenuBar::item:selected {\n" - " background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgba(106,106,106,255),stop:1 rgba(106,106,106,75));\n" - " border:1px solid %1;\n" - "}\n" - "QMenuBar::item:pressed {\n" - " background-color:%1;\n" - " border-left:1px solid rgba(25,25,25,127);\n" - " border-right:1px solid rgba(25,25,25,127);\n" - "}\n" - "QMenu {\n" - " background-color:rgb(45,45,45);\n" - " border:1px solid palette(shadow);\n" - "}\n" - "QMenu::item {\n" - " padding:3px 25px 3px 25px;\n" - " border:1px solid transparent;\n" - "}\n" - "QMenu::item:disabled {\n" - " color:rgb(127,127,127);\n" - "}\n" - "QMenu::item:selected {\n" - " border-color:rgba(200,200,200,127);\n" - " background-color:%1;\n" - "}\n" - "QMenu::icon:checked {\n" - " background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - " border:1px solid %1;\n" - " border-radius:2px;\n" - "}\n" - "QMenu::separator {\n" - " height:1px;\n" - " background-color:rgb(100,100,100);\n" - " margin-left:5px;\n" - " margin-right:5px;\n" - "}\n" - "QMenu::indicator {\n" - " width:18px;\n" - " height:18px;\n" - "}\n" - "QToolBar::top {\n" - " background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - " border-bottom:3px solid qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - "}\n" - "QToolBar::bottom {\n" - " background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - " border-top:3px solid qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - "}\n" - "QToolBar::left {\n" - " background-color:qlineargradient(x1:0,y1:0,x2:1,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - " border-right:3px solid qlineargradient(x1:0,y1:0,x2:1,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - "}\n" - "QToolBar::right {\n" - " background-color:qlineargradient(x1:1,y1:0,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - " border-left:3px solid qlineargradient(x1:1,y1:0,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - "}\n" - "QMainWindow {\n" - " background-color:rgb(53,53,53);\n" - "}\n" - "QMainWindow::separator {\n" - " width:6px;\n" - " height:5px;\n" - " padding:2px;\n" - " background-color:rgba(25,25,25,50%);\n" - "}\n" - "QLineEdit {\n" - " color:white;\n" - " background-color:rgb(25,25,25);\n" - "}\n" - "QLineEdit::focus {\n" - " border:1px solid %1;\n" - " border-radius:3px;\n" - " color:white;\n" - " background-color:rgb(25,25,25);\n" - "}\n" - "QSplitter::handle:horizontal {\n" - " width:10px;\n" - "}\n" - "QSplitter::handle:vertical {\n" - " height:10px;\n" - "}\n" - "QMainWindow::separator:hover, QSplitter::handle:hover {\n" - "}\n" - "QDockWidget::title {\n" - " padding:4px;\n" - " background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,175),stop:1 rgba(53,53,53,75));\n" - " border:1px solid rgba(25,25,25,75);\n" - " border-top:1px solid rgba(175,175,175,50%);\n" - " border-bottom:1px solid rgba(25,25,25,127);\n" - "}\n" - "QDockWidget::close-button, QDockWidget::float-button {\n" - " subcontrol-position:top right;\n" - " subcontrol-origin:margin;\n" - " position:absolute;\n" - " top:3px;\n" - " bottom:0px;\n" - " width:20px;\n" - " height:20px;\n" - "}\n" - "QDockWidget::close-button:hover, QDockWidget::float-button:hover {\n" - " border:1px solid %1;\n" - " border-radius:4px;\n" - "}\n" - "QDockWidget::close-button {\n" - " right:3px;\n" - "}\n" - "QDockWidget::float-button {\n" - " right:25px;\n" - "}\n" - "QGroupBox {\n" - " background-color:rgba(66,66,66,50%);\n" - " margin-top:27px;\n" - " border:1px solid rgba(25,25,25,127);\n" - " border-top-left-radius:4px;\n" - " border-top-right-radius:4px;\n" - "}\n" - "QGroupBox::title {\n" - " subcontrol-origin:margin;\n" - " subcontrol-position:left top;\n" - " padding:4px 6px;\n" - " margin-left:3px;\n" - " background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - " border:1px solid rgba(25,25,25,75);\n" - " border-top-left-radius:4px;\n" - " border-top-right-radius:4px;\n" - "}\n" - "QTabWidget::pane {\n" - " background-color:rgba(66,66,66,50%);\n" - "}\n" - "QTabWidget::tab-bar {\n" - "}\n" - "QTabBar {\n" - " background-color:transparent;\n" - " qproperty-drawBase:0;\n" - " border-bottom:1px solid rgba(25,25,25,50%);\n" - "}\n" - "QTabBar::tab {\n" - " padding:4px 6px;\n" - " background-color:rgba(25,25,25,127);\n" - " border:1px solid rgba(25,25,25,75);\n" - "}\n" - "QTabBar::tab:selected {\n" - " background-color:rgb(66,66,66);\n" - " border-bottom-color:rgba(66,66,66,75%);\n" - "}\n" - "QTabBar::tab:!selected {\n" - " color:rgb(175,175,175);\n" - "}\n" - "QComboBox {\n" - " min-height:20px;\n" - " padding:1px 18px 1px 3px;\n" - "}\n" - "QComboBox::focus {\n" - " background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,50), stop: 1 rgba(100,100,100,25));\n" - " border:1px solid %1;\n" - " border-radius:4px;\n" - "}\n" - "QComboBox::hover {\n" - " background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,50), stop: 1 rgba(127,127,127,50));\n" - " border:1px solid %1;\n" - " border-radius:4px;\n" - "}\n" - "QComboBox::drop-down {\n" - " background-color:transparent;\n" - "}\n" - "QComboBox::selected:on, QComboBox::selected:off {\n" - " background-color:%1;\n" - "}\n" - "QTabBar::tab:hover {\n" - " color:white;\n" - " background-color:%1;\n" - "}\n" - "QComboBox::separator {\n" - " background-color:rgb(100,100,100);\n" - " height:1px;\n" - " margin-left:4px;\n" - " margin-right:4px;\n" - "}\n" - "QCheckBox::indicator {\n" - " width:18px;\n" - " height:18px;\n" - "}\n" - "QPushButton {\n" - " min-height:20px;\n" - " min-width:80px;\n" - " padding:1px 3px 1px 3px;\n" - " outline:none;\n" - "}\n" - "QPushButton::focus, QToolButton::focus {\n" - " background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,50), stop: 1 rgba(100,100,100,25));\n" - " border:1px solid %1;\n" - " border-radius:4px;\n" - "}\n" - "QPushButton::hover, QToolButton::hover {\n" - " background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,75), stop: 1 rgba(100,100,100,50));\n" - " border:1px solid %1;\n" - " border-radius:4px;\n" - "}\n" - "QPushButton::pressed, QToolButton::pressed {\n" - " background-color:transparent;\n" - " border:1px solid %1;\n" - " border-radius:4px;\n" - "}\n" - "QPushButton[flat=\"true\"] {\n" - " background-color: transparent;\n" - "}\n" - "QRadioButton::indicator {\n" - " width:18px;\n" - " height:18px;\n" - "}\n" - "QListWidget::item:selected, QTreeView::item:selected, QTableView::item:selected {\n" - " color:white;\n" - " background-color:%1;\n" - "}\n" - "QTreeView {\n" - " background-color:rgb(25,25,25);\n" - " selection-background-color:%1;\n" - "}\n" - "QTreeView::branch:selected {\n" - " background-color:%1;\n" - "}\n" - "QTreeView::item:selected:disabled, QTableView::item:selected:disabled {\n" - " background-color:rgb(80,80,80);\n" - "}\n" - "QTreeView::branch:open, QTreeView::branch:closed {\n" - " background-color:solid;\n" - "}\n" - "QTableView, QListWidget {\n" - " background-color:rgb(25,25,25);\n" - "}\n" - "QTreeView QHeaderView::section, QTableView QHeaderView::section {\n" - " /*height:24px;*/\n" - " background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - " border-style:none;\n" - " border-bottom:1px solid rgb(65,65,65);\n" - " padding-left:5px;\n" - " padding-right:5px;\n" - "}\n" - "QTableWidget {\n" - " background-color:rgb(25,25,25);\n" - " alternate-background-color:rgb(40,40,40);\n" - "}\n" - "QScrollBar:vertical, QScrollBar:horizontal {\n" - " background-color:rgb(35,35,35);\n" - "}\n" - "QScrollBar::handle:vertical, QScrollBar::handle:horizontal {\n" - " background-color:rgb(65,65,65);\n" - " border-right:1px solid rgba(175,175,175,50%);\n" - " border-top:1px solid rgba(175,175,175,50%);\n" - " border-bottom:1px solid rgba(25,25,25,75);\n" - " border-radius:2px;\n" - "}\n" - "QScrollBar::handle:horizontal:hover, QScrollBar::handle:vertical:hover {\n" - " border:1px solid %1;\n" - " background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,75), stop: 1 rgba(127,127,127,75));\n" - "}\n" - "QScrollBar:vertical {\n" - " border-top-right-radius:2px;\n" - " border-bottom-right-radius:2px;\n" - " width:16px;\n" - " margin:0px;\n" - "}\n" - "QScrollBar::handle:vertical {\n" - " min-height:20px;\n" - " margin:2px 4px 2px 4px;\n" - "}\n" - "QScrollBar::add-line:vertical {\n" - " background:none;\n" - " height:0px;\n" - " subcontrol-position:right;\n" - " subcontrol-origin:margin;\n" - "}\n" - "QScrollBar::sub-line:vertical {\n" - " background:none;\n" - " height:0px;\n" - " subcontrol-position:left;\n" - " subcontrol-origin:margin;\n" - "}\n" - "QScrollBar:horizontal {\n" - " height:16px;\n" - " margin:0px;\n" - "}\n" - "QScrollBar::handle:horizontal {\n" - " min-width:20px;\n" - " margin:4px 2px 4px 2px;\n" - "}\n" - "QScrollBar::add-line:horizontal {\n" - " background:none;\n" - " width:0px;\n" - " subcontrol-position:bottom;\n" - " subcontrol-origin:margin;\n" - "}\n" - "QScrollBar::sub-line:horizontal {\n" - " background:none;\n" - " width:0px;\n" - " subcontrol-position:top;\n" - " subcontrol-origin:margin;\n" - "}\n" - "QSlider::sub-page {\n" - " background:%1;\n" - "}\n" - "QSlider::groove:vertical {\n" - " width:3px;\n" - " background:rgb(25,25,25);\n" - "}\n" - "QSlider::handle:vertical {\n" - " background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(175,175,175), stop: 1 rgb(75,75,75));\n" - " border:1px solid rgb(35,35,35);\n" - " border-radius:2px;\n" - " height:16px;\n" - " margin:0 -4px;\n" - "}\n" - "QSlider::handle:vertical:hover {\n" - " background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(200,200,200), stop: 1 rgba(100,100,100));\n" - " border:1px solid %1;\n" - " border-radius:2px;\n" - " height:16px;\n" - " margin:0 -4px;\n" - "}\n" - "QSlider::groove:horizontal {\n" - " height:3px;\n" - " background:rgb(25,25,25);\n" - "}\n" - "QSlider::handle:horizontal {\n" - " background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(175,175,175), stop: 1 rgb(75,75,75));\n" - " border:1px solid rgb(35,35,35);\n" - " border-radius:2px;\n" - " width:16px;\n" - " margin:-4px 0;\n" - "}\n" - "QSlider::handle:horizontal:hover {\n" - " background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(200,200,200), stop: 1 rgba(100,100,100));\n" - " border:1px solid %1;\n" - " border-radius:2px;\n" - " width:16px;\n" - " margin:-4px 0;\n" - "}\n" - "QStatusBar {\n" - " color:white;\n" - " background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75));\n" - "}\n" - "QStatusBar QLabel {\n" - " background-color:transparent;\n" - "}\n" - "QSizeGrip {\n" - " background-color:solid;\n" - "}\n" - "ThumbnailWidget#thumbnailWidget, ThumbnailLabel#thumbnailGridLabel, QLabel#thumbnailQLabel {\n" - " background-color:rgb(40,40,40);\n" - "}\n" - "ThumbnailWidget#thumbnailWidgetSelected {\n" - " background-color:rgb(40,40,40);\n" - " border:3px solid %1;\n" - "}\n" - "QScrollArea QWidget {\n" - "background:rgb(25,25,25);\n" - "}\n" -); +static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( + QWidget { + color:white; + background-color:rgb(53,53,53); + selection-background-color:%1; + } + QWidget#playlistWidget, QWidget#browserWidget, QWidget#tableWidget, QWidget#logWidget { + background-color:rgb(66,66,66); + border-top:1px solid rgba(175,175,175,50%); + border-left:1px solid rgba(125,125,125,50%); + border-right:1px solid rgba(125,125,125,50%); + border-bottom:1px solid rgba(25,25,25,75%); + } + QTextEdit, LogTextEdit { + background-color:rgb(25,25,25); + } + QSpinBox, QCheckBox { + background-color:rgb(25,25,25); + } + QCheckBox:checked, QCheckBox:unchecked { + background-color:rgb(53,53,53); + } + QDialog#shaderParamsDialog { + background-color:rgb(25,25,25); + } + QDialog#shaderParamsDialog QGroupBox, QDialog#shaderParamsDialog QGroupBox QLabel, + QDialog#shaderParamsDialog QGroupBox QSlider, QDialog#shaderParamsDialog QGroupBox QCheckBox:checked, + QDialog#shaderParamsDialog QGroupBox QCheckBox:unchecked { + background-color:rgb(53,53,53); + } + QDialog#shaderParamsDialog QGroupBox { + border-top-left-radius: 0px; + } + QDialog#shaderParamsDialog QGroupBox::title { + margin-left:0px; + min-height:28px; + padding:4px 10px; + background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgb(53,53,53),stop:1 rgba(125,125,125,127)); + border:1px solid rgba(25,25,25,75); + border-top:1px solid rgba(175,175,175,50%); + border-bottom: none transparent; + } + QToolTip { + color:white; + background-color:rgb(53,53,53); + border:1px solid rgb(80,80,80); + border-radius:4px; + } + QMenuBar { + background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + border-bottom:2px solid rgba(25,25,25,75); + } + QMenuBar::item { + spacing:2px; + padding:3px 4px; + background-color:transparent; + } + QMenuBar::item:selected { + background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgba(106,106,106,255),stop:1 rgba(106,106,106,75)); + border:1px solid %1; + } + QMenuBar::item:pressed { + background-color:%1; + border-left:1px solid rgba(25,25,25,127); + border-right:1px solid rgba(25,25,25,127); + } + QMenu { + background-color:rgb(45,45,45); + border:1px solid palette(shadow); + } + QMenu::item { + padding:3px 25px 3px 25px; + border:1px solid transparent; + } + QMenu::item:disabled { + color:rgb(127,127,127); + } + QMenu::item:selected { + border-color:rgba(200,200,200,127); + background-color:%1; + } + QMenu::icon:checked { + background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + border:1px solid %1; + border-radius:2px; + } + QMenu::separator { + height:1px; + background-color:rgb(100,100,100); + margin-left:5px; + margin-right:5px; + } + QMenu::indicator { + width:18px; + height:18px; + } + QToolBar::top { + background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + border-bottom:3px solid qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + } + QToolBar::bottom { + background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + border-top:3px solid qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + } + QToolBar::left { + background-color:qlineargradient(x1:0,y1:0,x2:1,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + border-right:3px solid qlineargradient(x1:0,y1:0,x2:1,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + } + QToolBar::right { + background-color:qlineargradient(x1:1,y1:0,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + border-left:3px solid qlineargradient(x1:1,y1:0,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + } + QMainWindow { + background-color:rgb(53,53,53); + } + QMainWindow::separator { + width:6px; + height:5px; + padding:2px; + background-color:rgba(25,25,25,50%); + } + QLineEdit { + color:white; + background-color:rgb(25,25,25); + } + QLineEdit::focus { + border:1px solid %1; + border-radius:3px; + color:white; + background-color:rgb(25,25,25); + } + QSplitter::handle:horizontal { + width:10px; + } + QSplitter::handle:vertical { + height:10px; + } + QMainWindow::separator:hover, QSplitter::handle:hover { + } + QDockWidget::title { + padding:4px; + background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,175),stop:1 rgba(53,53,53,75)); + border:1px solid rgba(25,25,25,75); + border-top:1px solid rgba(175,175,175,50%); + border-bottom:1px solid rgba(25,25,25,127); + } + QDockWidget::close-button, QDockWidget::float-button { + subcontrol-position:top right; + subcontrol-origin:margin; + position:absolute; + top:3px; + bottom:0px; + width:20px; + height:20px; + } + QDockWidget::close-button:hover, QDockWidget::float-button:hover { + border:1px solid %1; + border-radius:4px; + } + QDockWidget::close-button { + right:3px; + } + QDockWidget::float-button { + right:25px; + } + QGroupBox { + background-color:rgba(66,66,66,50%); + margin-top:27px; + border:1px solid rgba(25,25,25,127); + border-top-left-radius:4px; + border-top-right-radius:4px; + } + QGroupBox::title { + subcontrol-origin:margin; + subcontrol-position:left top; + padding:4px 6px; + margin-left:3px; + background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + border:1px solid rgba(25,25,25,75); + border-top-left-radius:4px; + border-top-right-radius:4px; + } + QTabWidget::pane { + background-color:rgba(66,66,66,50%); + } + QTabWidget::tab-bar { + } + QTabBar { + background-color:transparent; + qproperty-drawBase:0; + border-bottom:1px solid rgba(25,25,25,50%); + } + QTabBar::tab { + padding:4px 6px; + background-color:rgba(25,25,25,127); + border:1px solid rgba(25,25,25,75); + } + QTabBar::tab:selected { + background-color:rgb(66,66,66); + border-bottom-color:rgba(66,66,66,75%); + } + QTabBar::tab:!selected { + color:rgb(175,175,175); + } + QComboBox { + min-height:20px; + padding:1px 18px 1px 3px; + } + QComboBox::focus { + background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,50), stop: 1 rgba(100,100,100,25)); + border:1px solid %1; + border-radius:4px; + } + QComboBox::hover { + background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,50), stop: 1 rgba(127,127,127,50)); + border:1px solid %1; + border-radius:4px; + } + QComboBox::drop-down { + background-color:transparent; + } + QComboBox::selected:on, QComboBox::selected:off { + background-color:%1; + } + QTabBar::tab:hover { + color:white; + background-color:%1; + } + QComboBox::separator { + background-color:rgb(100,100,100); + height:1px; + margin-left:4px; + margin-right:4px; + } + QCheckBox::indicator { + width:18px; + height:18px; + } + QPushButton { + min-height:20px; + min-width:80px; + padding:1px 3px 1px 3px; + outline:none; + } + QPushButton::focus, QToolButton::focus { + background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,50), stop: 1 rgba(100,100,100,25)); + border:1px solid %1; + border-radius:4px; + } + QPushButton::hover, QToolButton::hover { + background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,75), stop: 1 rgba(100,100,100,50)); + border:1px solid %1; + border-radius:4px; + } + QPushButton::pressed, QToolButton::pressed { + background-color:transparent; + border:1px solid %1; + border-radius:4px; + } + QPushButton[flat="true"] { + background-color: transparent; + } + QRadioButton::indicator { + width:18px; + height:18px; + } + QListWidget::item:selected, QTreeView::item:selected, QTableView::item:selected { + color:white; + background-color:%1; + } + QTreeView { + background-color:rgb(25,25,25); + selection-background-color:%1; + } + QTreeView::branch:selected { + background-color:%1; + } + QTreeView::item:selected:disabled, QTableView::item:selected:disabled { + background-color:rgb(80,80,80); + } + QTreeView::branch:open, QTreeView::branch:closed { + background-color:solid; + } + QTableView, QListWidget { + background-color:rgb(25,25,25); + } + QTreeView QHeaderView::section, QTableView QHeaderView::section { + /*height:24px;*/ + background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + border-style:none; + border-bottom:1px solid rgb(65,65,65); + padding-left:5px; + padding-right:5px; + } + QTableWidget { + background-color:rgb(25,25,25); + alternate-background-color:rgb(40,40,40); + } + QScrollBar:vertical, QScrollBar:horizontal { + background-color:rgb(35,35,35); + } + QScrollBar::handle:vertical, QScrollBar::handle:horizontal { + background-color:rgb(65,65,65); + border-right:1px solid rgba(175,175,175,50%); + border-top:1px solid rgba(175,175,175,50%); + border-bottom:1px solid rgba(25,25,25,75); + border-radius:2px; + } + QScrollBar::handle:horizontal:hover, QScrollBar::handle:vertical:hover { + border:1px solid %1; + background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,75), stop: 1 rgba(127,127,127,75)); + } + QScrollBar:vertical { + border-top-right-radius:2px; + border-bottom-right-radius:2px; + width:16px; + margin:0px; + } + QScrollBar::handle:vertical { + min-height:20px; + margin:2px 4px 2px 4px; + } + QScrollBar::add-line:vertical { + background:none; + height:0px; + subcontrol-position:right; + subcontrol-origin:margin; + } + QScrollBar::sub-line:vertical { + background:none; + height:0px; + subcontrol-position:left; + subcontrol-origin:margin; + } + QScrollBar:horizontal { + height:16px; + margin:0px; + } + QScrollBar::handle:horizontal { + min-width:20px; + margin:4px 2px 4px 2px; + } + QScrollBar::add-line:horizontal { + background:none; + width:0px; + subcontrol-position:bottom; + subcontrol-origin:margin; + } + QScrollBar::sub-line:horizontal { + background:none; + width:0px; + subcontrol-position:top; + subcontrol-origin:margin; + } + QSlider::sub-page { + background:%1; + } + QSlider::groove:vertical { + width:3px; + background:rgb(25,25,25); + } + QSlider::handle:vertical { + background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(175,175,175), stop: 1 rgb(75,75,75)); + border:1px solid rgb(35,35,35); + border-radius:2px; + height:16px; + margin:0 -4px; + } + QSlider::handle:vertical:hover { + background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(200,200,200), stop: 1 rgba(100,100,100)); + border:1px solid %1; + border-radius:2px; + height:16px; + margin:0 -4px; + } + QSlider::groove:horizontal { + height:3px; + background:rgb(25,25,25); + } + QSlider::handle:horizontal { + background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(175,175,175), stop: 1 rgb(75,75,75)); + border:1px solid rgb(35,35,35); + border-radius:2px; + width:16px; + margin:-4px 0; + } + QSlider::handle:horizontal:hover { + background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(200,200,200), stop: 1 rgba(100,100,100)); + border:1px solid %1; + border-radius:2px; + width:16px; + margin:-4px 0; + } + QStatusBar { + color:white; + background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgba(25,25,25,127),stop:1 rgba(53,53,53,75)); + } + QStatusBar QLabel { + background-color:transparent; + } + QSizeGrip { + background-color:solid; + } + ThumbnailWidget#thumbnailWidget, ThumbnailLabel#thumbnailGridLabel, QLabel#thumbnailQLabel { + background-color:rgb(40,40,40); + } + ThumbnailWidget#thumbnailWidgetSelected { + background-color:rgb(40,40,40); + border:3px solid %1; + } + QScrollArea QWidget { + background:rgb(25,25,25); + } +)"); From 0175effb00c695e789269f4abeb5b7805d17a7f6 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 16:39:20 +0200 Subject: [PATCH 043/182] Revert "(Menu) change strncpy to strlcpy" This reverts commit ba676239619581076460d387fbec33cd94bb05de. --- menu/cbs/menu_cbs_ok.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 51c2a5c6b2..9de84c207b 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -993,7 +993,7 @@ static bool menu_content_playlist_load(playlist_t *playlist, size_t idx) path_check = (char *) calloc(strlen(path_tolower) + 1, sizeof(char)); - strlcpy(path_check, path, strlen(path_tolower)); + strncpy(path_check, path, strlen(path_tolower)); valid_path = path_is_valid(path_check); From 6cd6bf993f91e9ca5259dedc515021824280ab36 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 18:30:53 +0200 Subject: [PATCH 044/182] Fix strlcpy call --- menu/cbs/menu_cbs_ok.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 9de84c207b..5991b04d77 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -993,7 +993,7 @@ static bool menu_content_playlist_load(playlist_t *playlist, size_t idx) path_check = (char *) calloc(strlen(path_tolower) + 1, sizeof(char)); - strncpy(path_check, path, strlen(path_tolower)); + strlcpy(path_check, path, strlen(path_tolower) + 1); valid_path = path_is_valid(path_check); From 220c84c7a35f31f0b44c99df1793c72680458131 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 18:53:19 +0200 Subject: [PATCH 045/182] Fix strlcat size arguments --- managers/cheat_manager.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/managers/cheat_manager.c b/managers/cheat_manager.c index 67abbb0bab..81ccdc64ba 100644 --- a/managers/cheat_manager.c +++ b/managers/cheat_manager.c @@ -608,15 +608,15 @@ bool cheat_manager_get_game_specific_filename(char * cheat_filename, size_t max_ return false ; cheat_filename[0] = '\0'; - strlcat(cheat_filename, settings->paths.path_cheat_database, max_length-1) ; - fill_pathname_slash(cheat_filename, max_length) ; - strlcat(cheat_filename, core_name, max_length-strlen(cheat_filename)-1) ; - fill_pathname_slash(cheat_filename, max_length) ; + strlcat(cheat_filename, settings->paths.path_cheat_database, max_length); + fill_pathname_slash(cheat_filename, max_length); + strlcat(cheat_filename, core_name, max_length); + fill_pathname_slash(cheat_filename, max_length); if (!filestream_exists(cheat_filename)) path_mkdir(cheat_filename); - strlcat(cheat_filename, game_name, max_length-strlen(cheat_filename)-1) ; + strlcat(cheat_filename, game_name, max_length); return true ; From 9221e4e845e193f6e7eb6cbd5c4e0a30e0695c40 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 16 Aug 2018 13:08:29 -0400 Subject: [PATCH 046/182] Discord integration requires a C++ linker --- Makefile.common | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.common b/Makefile.common index 5f4106db23..7799e67183 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1735,6 +1735,7 @@ ifeq ($(HAVE_NETWORKING), 1) endif ifeq ($(HAVE_DISCORD), 1) + NEED_CXX_LINKER = 1 DEFINES += -DHAVE_DISCORD DEFINES += -Ideps/discord-rpc/include/ -Ideps/discord-rpc/thirdparty/rapidjson-1.1.0/include/ OBJ += deps/discord-rpc/src/discord_rpc.o \ From d3c6fc1601b1d6581b15107cc2e7c4b99b23b411 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 19:28:33 +0200 Subject: [PATCH 047/182] Add initial MSVC 2012 solution --- pkg/msvc/RetroArch-msvc2012.sln | 20 +++++ pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj | 90 +++++++++++++++++++ .../RetroArch-msvc2012.vcxproj.filters | 28 ++++++ 3 files changed, 138 insertions(+) create mode 100644 pkg/msvc/RetroArch-msvc2012.sln create mode 100644 pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj create mode 100644 pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj.filters diff --git a/pkg/msvc/RetroArch-msvc2012.sln b/pkg/msvc/RetroArch-msvc2012.sln new file mode 100644 index 0000000000..39a084d720 --- /dev/null +++ b/pkg/msvc/RetroArch-msvc2012.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc-2012", "msvc-2012\RetroArch-msvc2012.vcxproj", "{E1D4BAA1-50DB-428E-9462-4F1B31E38119}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E1D4BAA1-50DB-428E-9462-4F1B31E38119}.Debug|Win32.ActiveCfg = Debug|Win32 + {E1D4BAA1-50DB-428E-9462-4F1B31E38119}.Debug|Win32.Build.0 = Debug|Win32 + {E1D4BAA1-50DB-428E-9462-4F1B31E38119}.Release|Win32.ActiveCfg = Release|Win32 + {E1D4BAA1-50DB-428E-9462-4F1B31E38119}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj b/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj new file mode 100644 index 0000000000..20cac85fed --- /dev/null +++ b/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj @@ -0,0 +1,90 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {E1D4BAA1-50DB-428E-9462-4F1B31E38119} + Win32Proj + msvc2012 + RetroArch-msvc2012 + + + + Application + true + v110 + Unicode + + + Application + false + v110 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + CompileAsC + CompileAsC + + + + + + + + \ No newline at end of file diff --git a/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj.filters b/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj.filters new file mode 100644 index 0000000000..0d9661f43a --- /dev/null +++ b/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj.filters @@ -0,0 +1,28 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file From 12539f310d38ec6989d18a254c9745617cbc8a51 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 16 Aug 2018 13:35:04 -0400 Subject: [PATCH 048/182] use strl functions --- gfx/drivers/d3d10.c | 15 ++++++--------- gfx/drivers/d3d11.c | 16 ++++++---------- gfx/drivers/d3d12.c | 15 ++++++--------- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/gfx/drivers/d3d10.c b/gfx/drivers/d3d10.c index ea557a2084..474c71294b 100644 --- a/gfx/drivers/d3d10.c +++ b/gfx/drivers/d3d10.c @@ -393,20 +393,17 @@ static bool d3d10_gfx_set_shader(void* data, #endif static const char vs_ext[] = ".vs.hlsl"; static const char ps_ext[] = ".ps.hlsl"; - char vs_path[PATH_MAX_LENGTH]; - char ps_path[PATH_MAX_LENGTH]; + char vs_path[PATH_MAX_LENGTH] = {0}; + char ps_path[PATH_MAX_LENGTH] = {0}; const char* slang_path = d3d10->shader_preset->pass[i].source.path; const char* vs_src = d3d10->shader_preset->pass[i].source.string.vertex; const char* ps_src = d3d10->shader_preset->pass[i].source.string.fragment; int base_len = strlen(slang_path) - strlen(".slang"); - if (base_len <= 0) - base_len = strlen(slang_path); - - strncpy(vs_path, slang_path, base_len); - strncpy(ps_path, slang_path, base_len); - strncpy(vs_path + base_len, vs_ext, sizeof(vs_ext)); - strncpy(ps_path + base_len, ps_ext, sizeof(ps_ext)); + strlcpy(vs_path, slang_path, sizeof(vs_path)); + strlcpy(ps_path, slang_path, sizeof(ps_path)); + strlcat(vs_path, vs_ext, sizeof(vs_path)); + strlcat(ps_path, ps_ext, sizeof(ps_path)); if (!d3d10_init_shader( d3d10->device, vs_src, 0, vs_path, "main", NULL, NULL, desc, countof(desc), diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index 3a96048a38..66cdaf990c 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -407,20 +407,16 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const #endif static const char vs_ext[] = ".vs.hlsl"; static const char ps_ext[] = ".ps.hlsl"; - char vs_path[PATH_MAX_LENGTH]; - char ps_path[PATH_MAX_LENGTH]; + char vs_path[PATH_MAX_LENGTH] = {0}; + char ps_path[PATH_MAX_LENGTH] = {0}; const char* slang_path = d3d11->shader_preset->pass[i].source.path; const char* vs_src = d3d11->shader_preset->pass[i].source.string.vertex; const char* ps_src = d3d11->shader_preset->pass[i].source.string.fragment; - int base_len = strlen(slang_path) - strlen(".slang"); - if (base_len <= 0) - base_len = strlen(slang_path); - - strncpy(vs_path, slang_path, base_len); - strncpy(ps_path, slang_path, base_len); - strncpy(vs_path + base_len, vs_ext, sizeof(vs_ext)); - strncpy(ps_path + base_len, ps_ext, sizeof(ps_ext)); + strlcpy(vs_path, slang_path, sizeof(vs_path)); + strlcpy(ps_path, slang_path, sizeof(ps_path)); + strlcat(vs_path, vs_ext, sizeof(vs_path)); + strlcat(ps_path, ps_ext, sizeof(ps_path)); if (!d3d11_init_shader( d3d11->device, vs_src, 0, vs_path, "main", NULL, NULL, desc, countof(desc), diff --git a/gfx/drivers/d3d12.c b/gfx/drivers/d3d12.c index 4f7e884c0c..b64fa654f2 100644 --- a/gfx/drivers/d3d12.c +++ b/gfx/drivers/d3d12.c @@ -420,20 +420,17 @@ static bool d3d12_gfx_set_shader(void* data, enum rarch_shader_type type, const #endif static const char vs_ext[] = ".vs.hlsl"; static const char ps_ext[] = ".ps.hlsl"; - char vs_path[PATH_MAX_LENGTH]; - char ps_path[PATH_MAX_LENGTH]; + char vs_path[PATH_MAX_LENGTH] = {0}; + char ps_path[PATH_MAX_LENGTH] = {0}; const char* slang_path = d3d12->shader_preset->pass[i].source.path; const char* vs_src = d3d12->shader_preset->pass[i].source.string.vertex; const char* ps_src = d3d12->shader_preset->pass[i].source.string.fragment; int base_len = strlen(slang_path) - strlen(".slang"); - if (base_len <= 0) - base_len = strlen(slang_path); - - strncpy(vs_path, slang_path, base_len); - strncpy(ps_path, slang_path, base_len); - strncpy(vs_path + base_len, vs_ext, sizeof(vs_ext)); - strncpy(ps_path + base_len, ps_ext, sizeof(ps_ext)); + strlcpy(vs_path, slang_path, sizeof(vs_path)); + strlcpy(ps_path, slang_path, sizeof(ps_path)); + strlcat(vs_path, vs_ext, sizeof(vs_path)); + strlcat(ps_path, ps_ext, sizeof(ps_path)); if (!d3d_compile(vs_src, 0, vs_path, "main", "vs_5_0", &vs_code)) save_hlsl = true; From a1d5b0fd0378e4e4e67c573973d3c1f11f089717 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 20:49:31 +0200 Subject: [PATCH 049/182] Update MSVC 2012 solution --- gfx/common/dxgi_common.h | 4 +- gfx/common/vulkan_common.c | 5 +- gfx/drivers/d3d10.c | 162 ++++++++--------- gfx/drivers/d3d11.c | 163 +++++++++--------- menu/drivers_display/menu_display_d3d10.c | 6 +- menu/drivers_display/menu_display_d3d11.c | 6 +- pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj | 6 +- 7 files changed, 181 insertions(+), 171 deletions(-) diff --git a/gfx/common/dxgi_common.h b/gfx/common/dxgi_common.h index 32af9b89b2..0323b5d839 100644 --- a/gfx/common/dxgi_common.h +++ b/gfx/common/dxgi_common.h @@ -804,6 +804,7 @@ RETRO_END_DECLS #ifndef PERF_START #define PERF_START() \ + { \ static struct retro_perf_counter perfcounter = { __FUNCTION__ }; \ LARGE_INTEGER start, stop; \ rarch_perf_register(&perfcounter); \ @@ -812,7 +813,8 @@ RETRO_END_DECLS #define PERF_STOP() \ QueryPerformanceCounter(&stop); \ - perfcounter.total += stop.QuadPart - start.QuadPart + perfcounter.total += stop.QuadPart - start.QuadPart; \ + } #endif #else #define PERF_START() diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 31c7f3d620..8a38a4855c 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -1969,11 +1969,12 @@ static bool vulkan_create_display_surface(gfx_ctx_vulkan_data_t *vk, retry: for (dpy = 0; dpy < display_count; dpy++) { + VkDisplayKHR display; if (monitor_index != 0 && (monitor_index - 1) != dpy) continue; - VkDisplayKHR display = displays[dpy].display; - best_mode = VK_NULL_HANDLE; + display = displays[dpy].display; + best_mode = VK_NULL_HANDLE; best_plane = UINT32_MAX; if (vkGetDisplayModePropertiesKHR(vk->context.gpu, diff --git a/gfx/drivers/d3d10.c b/gfx/drivers/d3d10.c index 474c71294b..dd08fdf786 100644 --- a/gfx/drivers/d3d10.c +++ b/gfx/drivers/d3d10.c @@ -43,10 +43,10 @@ static void d3d10_free_overlays(d3d10_video_t* d3d10) Release(d3d10->overlays.vbo); } -static void + static void d3d10_overlay_vertex_geom(void* data, unsigned index, float x, float y, float w, float h) { - d3d10_sprite_t* sprites = NULL; + d3d10_sprite_t* sprites = NULL; d3d10_video_t* d3d10 = (d3d10_video_t*)data; if (!d3d10) @@ -54,16 +54,16 @@ d3d10_overlay_vertex_geom(void* data, unsigned index, float x, float y, float w, D3D10MapBuffer(d3d10->overlays.vbo, D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&sprites); - sprites[index].pos.x = x; - sprites[index].pos.y = y; - sprites[index].pos.w = w; - sprites[index].pos.h = h; + sprites[index].pos.x = x; + sprites[index].pos.y = y; + sprites[index].pos.w = w; + sprites[index].pos.h = h; D3D10UnmapBuffer(d3d10->overlays.vbo); } static void d3d10_overlay_tex_geom(void* data, unsigned index, float u, float v, float w, float h) { - d3d10_sprite_t* sprites = NULL; + d3d10_sprite_t* sprites = NULL; d3d10_video_t* d3d10 = (d3d10_video_t*)data; if (!d3d10) @@ -72,16 +72,16 @@ static void d3d10_overlay_tex_geom(void* data, unsigned index, float u, float v, D3D10MapBuffer( d3d10->overlays.vbo, D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&sprites); - sprites[index].coords.u = u; - sprites[index].coords.v = v; - sprites[index].coords.w = w; - sprites[index].coords.h = h; + sprites[index].coords.u = u; + sprites[index].coords.v = v; + sprites[index].coords.w = w; + sprites[index].coords.h = h; D3D10UnmapBuffer(d3d10->overlays.vbo); } static void d3d10_overlay_set_alpha(void* data, unsigned index, float mod) { - d3d10_sprite_t* sprites = NULL; + d3d10_sprite_t* sprites = NULL; d3d10_video_t* d3d10 = (d3d10_video_t*)data; if (!d3d10) @@ -90,10 +90,10 @@ static void d3d10_overlay_set_alpha(void* data, unsigned index, float mod) D3D10MapBuffer( d3d10->overlays.vbo, D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&sprites); - sprites[index].colors[0] = DXGI_COLOR_RGBA(0xFF, 0xFF, 0xFF, mod * 0xFF); - sprites[index].colors[1] = sprites[index].colors[0]; - sprites[index].colors[2] = sprites[index].colors[0]; - sprites[index].colors[3] = sprites[index].colors[0]; + sprites[index].colors[0] = DXGI_COLOR_RGBA(0xFF, 0xFF, 0xFF, mod * 0xFF); + sprites[index].colors[1] = sprites[index].colors[0]; + sprites[index].colors[2] = sprites[index].colors[0]; + sprites[index].colors[3] = sprites[index].colors[0]; D3D10UnmapBuffer(d3d10->overlays.vbo); } @@ -213,7 +213,7 @@ static void d3d10_set_filtering(void* data, unsigned index, bool smooth) static void d3d10_gfx_set_rotation(void* data, unsigned rotation) { - math_matrix_4x4 rot; + math_matrix_4x4 rot; void* mapped_ubo = NULL; d3d10_video_t* d3d10 = (d3d10_video_t*)data; @@ -242,7 +242,7 @@ static void d3d10_update_viewport(void* data, bool force_full) d3d10->frame.viewport.MaxDepth = 1.0f; if (d3d10->shader_preset && (d3d10->frame.output_size.x != d3d10->vp.width || - d3d10->frame.output_size.y != d3d10->vp.height)) + d3d10->frame.output_size.y != d3d10->vp.height)) d3d10->resize_render_targets = true; d3d10->frame.output_size.x = d3d10->vp.width; @@ -375,16 +375,16 @@ static bool d3d10_gfx_set_shader(void* data, /* clang-format on */ if (!slang_process( - d3d10->shader_preset, i, RARCH_SHADER_HLSL, 40, &semantics_map, - &d3d10->pass[i].semantics)) + d3d10->shader_preset, i, RARCH_SHADER_HLSL, 40, &semantics_map, + &d3d10->pass[i].semantics)) goto error; { static const D3D10_INPUT_ELEMENT_DESC desc[] = { { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_vertex_t, position), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_vertex_t, texcoord), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; #ifdef DEBUG bool save_hlsl = true; @@ -406,13 +406,13 @@ static bool d3d10_gfx_set_shader(void* data, strlcat(ps_path, ps_ext, sizeof(ps_path)); if (!d3d10_init_shader( - d3d10->device, vs_src, 0, vs_path, "main", NULL, NULL, desc, countof(desc), - &d3d10->pass[i].shader)) + d3d10->device, vs_src, 0, vs_path, "main", NULL, NULL, desc, countof(desc), + &d3d10->pass[i].shader)) save_hlsl = true; if (!d3d10_init_shader( - d3d10->device, ps_src, 0, ps_path, NULL, "main", NULL, NULL, 0, - &d3d10->pass[i].shader)) + d3d10->device, ps_src, 0, ps_path, NULL, "main", NULL, NULL, 0, + &d3d10->pass[i].shader)) save_hlsl = true; if (save_hlsl) @@ -543,16 +543,16 @@ static void d3d10_gfx_free(void* data) font_driver_free_osd(); #if 0 - if (video_driver_is_video_cache_context()) - { + if (video_driver_is_video_cache_context()) + { cached_device_d3d10 = d3d10->device; - cached_context = d3d10->context; - } - else + cached_context = d3d10->context; + } + else #endif - { - Release(d3d10->device); - } + { + Release(d3d10->device); + } win32_monitor_from_window(); win32_destroy_window(); @@ -590,7 +590,7 @@ d3d10_gfx_init(const video_info_t* video, d3d10->vp.full_height = current_mon.rcMonitor.bottom - current_mon.rcMonitor.top; - if (!win32_set_video_mode(d3d10, + if (!win32_set_video_mode(d3d10, d3d10->vp.full_width, d3d10->vp.full_height, video->fullscreen)) { RARCH_ERR("[D3D10]: win32_set_video_mode failed.\n"); @@ -613,9 +613,9 @@ d3d10_gfx_init(const video_info_t* video, desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Windowed = TRUE; - desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; + desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; #if 0 - desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; #endif @@ -625,9 +625,9 @@ d3d10_gfx_init(const video_info_t* video, #endif if (FAILED(D3D10CreateDeviceAndSwapChain( - NULL, D3D10_DRIVER_TYPE_HARDWARE, - NULL, flags, D3D10_SDK_VERSION, &desc, - (IDXGISwapChain**)&d3d10->swapChain, &d3d10->device))) + NULL, D3D10_DRIVER_TYPE_HARDWARE, + NULL, flags, D3D10_SDK_VERSION, &desc, + (IDXGISwapChain**)&d3d10->swapChain, &d3d10->device))) goto error; } @@ -639,7 +639,7 @@ d3d10_gfx_init(const video_info_t* video, Release(backBuffer); } - D3D10SetRenderTargets(d3d10->device, 1, &d3d10->renderTargetView, NULL); + D3D10SetRenderTargets(d3d10->device, 1, &d3d10->renderTargetView, NULL); video_driver_set_size(&d3d10->vp.full_width, &d3d10->vp.full_height); d3d10->viewport.Width = d3d10->vp.full_width; @@ -684,7 +684,7 @@ d3d10_gfx_init(const video_info_t* video, d3d10_gfx_set_rotation(d3d10, 0); { - D3D10_SAMPLER_DESC desc = { D3D10_FILTER_MIN_MAG_MIP_POINT }; + D3D10_SAMPLER_DESC desc = { D3D10_FILTER_MIN_MAG_MIP_POINT }; desc.MaxAnisotropy = 1; desc.ComparisonFunc = D3D10_COMPARISON_NEVER; desc.MinLOD = -D3D10_FLOAT32_MAX; @@ -756,52 +756,52 @@ d3d10_gfx_init(const video_info_t* video, { D3D10_INPUT_ELEMENT_DESC desc[] = { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_vertex_t, position), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_vertex_t, texcoord), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d10_vertex_t, color), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; static const char shader[] = #include "d3d_shaders/opaque_sm5.hlsl.h" - ; + ; if (!d3d10_init_shader( - d3d10->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", NULL, desc, - countof(desc), &d3d10->shaders[VIDEO_SHADER_STOCK_BLEND])) + d3d10->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", NULL, desc, + countof(desc), &d3d10->shaders[VIDEO_SHADER_STOCK_BLEND])) goto error; } { D3D10_INPUT_ELEMENT_DESC desc[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d10_sprite_t, pos), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d10_sprite_t, coords), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d10_sprite_t, colors[0]), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d10_sprite_t, colors[1]), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 2, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d10_sprite_t, colors[2]), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 3, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d10_sprite_t, colors[3]), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "PARAMS", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_sprite_t, params), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; static const char shader[] = #include "d3d_shaders/sprite_sm4.hlsl.h" - ; + ; if (!d3d10_init_shader( - d3d10->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", "GSMain", desc, - countof(desc), &d3d10->sprites.shader)) + d3d10->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", "GSMain", desc, + countof(desc), &d3d10->sprites.shader)) goto error; if (!d3d10_init_shader( - d3d10->device, shader, sizeof(shader), NULL, "VSMain", "PSMainA8", "GSMain", desc, - countof(desc), &d3d10->sprites.shader_font)) + d3d10->device, shader, sizeof(shader), NULL, "VSMain", "PSMainA8", "GSMain", desc, + countof(desc), &d3d10->sprites.shader_font)) goto error; } @@ -873,7 +873,7 @@ d3d10_gfx_init(const video_info_t* video, } { - D3D10_BLEND_DESC blend_desc = { 0 }; + D3D10_BLEND_DESC blend_desc = { 0 }; blend_desc.AlphaToCoverageEnable = FALSE; blend_desc.BlendEnable[0] = TRUE; @@ -917,7 +917,7 @@ d3d10_gfx_init(const video_info_t* video, #if 0 if (video_driver_get_hw_context()->context_type == RETRO_HW_CONTEXT_DIRECT3D && - video_driver_get_hw_context()->version_major == 11) + video_driver_get_hw_context()->version_major == 11) { d3d10->hw.enable = true; d3d10->hw.iface.interface_type = RETRO_HW_RENDER_INTERFACE_D3D10; @@ -1023,7 +1023,7 @@ static void d3d10_init_render_targets(d3d10_video_t* d3d10, RARCH_LOG("[D3D10]: Updating framebuffer size %u x %u.\n", width, height); if ((i != (d3d10->shader_preset->passes - 1)) || (width != d3d10->vp.width) || - (height != d3d10->vp.height)) + (height != d3d10->vp.height)) { d3d10->pass[i].viewport.Width = width; d3d10->pass[i].viewport.Height = height; @@ -1104,7 +1104,7 @@ static bool d3d10_gfx_frame( #if 0 /* custom viewport doesn't call apply_state_changes, so we can't rely on this for now */ if (d3d10->resize_viewport) #endif - d3d10_update_viewport(d3d10, false); + d3d10_update_viewport(d3d10, false); D3D10SetPrimitiveTopology(context, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); @@ -1121,7 +1121,7 @@ static bool d3d10_gfx_frame( if (d3d10->shader_preset) { if (d3d10->frame.texture[0].desc.Width != width || - d3d10->frame.texture[0].desc.Height != height) + d3d10->frame.texture[0].desc.Height != height) d3d10->resize_render_targets = true; if (d3d10->resize_render_targets) @@ -1157,7 +1157,7 @@ static bool d3d10_gfx_frame( /* either no history, or we moved a texture of a different size in the front slot */ if (d3d10->frame.texture[0].desc.Width != width || - d3d10->frame.texture[0].desc.Height != height) + d3d10->frame.texture[0].desc.Height != height) { d3d10->frame.texture[0].desc.Width = width; d3d10->frame.texture[0].desc.Height = height; @@ -1200,7 +1200,7 @@ static bool d3d10_gfx_frame( if (d3d10->shader_preset->pass[i].frame_count_mod) d3d10->pass[i].frame_count = - frame_count % d3d10->shader_preset->pass[i].frame_count_mod; + frame_count % d3d10->shader_preset->pass[i].frame_count_mod; else d3d10->pass[i].frame_count = frame_count; @@ -1328,19 +1328,19 @@ static bool d3d10_gfx_frame( else #endif if (video_info->statistics_show) - { - struct font_params* osd_params = (struct font_params*)&video_info->osd_stat_params; - - if (osd_params) { - D3D10SetViewports(context, 1, &d3d10->viewport); - D3D10SetBlendState(d3d10->device, d3d10->blend_enable, NULL, D3D10_DEFAULT_SAMPLE_MASK); - D3D10SetVertexBuffer(context, 0, d3d10->sprites.vbo, sizeof(d3d10_sprite_t), 0); - font_driver_render_msg( - video_info, NULL, video_info->stat_text, - (const struct font_params*)&video_info->osd_stat_params); + struct font_params* osd_params = (struct font_params*)&video_info->osd_stat_params; + + if (osd_params) + { + D3D10SetViewports(context, 1, &d3d10->viewport); + D3D10SetBlendState(d3d10->device, d3d10->blend_enable, NULL, D3D10_DEFAULT_SAMPLE_MASK); + D3D10SetVertexBuffer(context, 0, d3d10->sprites.vbo, sizeof(d3d10_sprite_t), 0); + font_driver_render_msg( + video_info, NULL, video_info->stat_text, + (const struct font_params*)&video_info->osd_stat_params); + } } - } #ifdef HAVE_OVERLAY if (d3d10->overlays.enabled) @@ -1383,7 +1383,7 @@ static void d3d10_gfx_set_nonblock_state(void* data, bool toggle) { d3d10_video_t* d3d10 = (d3d10_video_t*)data; - if (!d3d10) + if (!d3d10) return; d3d10->vsync = !toggle; @@ -1471,7 +1471,7 @@ static void d3d10_set_menu_texture_enable(void* data, bool state, bool full_scre { d3d10_video_t* d3d10 = (d3d10_video_t*)data; - if (!d3d10) + if (!d3d10) return; d3d10->menu.enabled = state; @@ -1571,7 +1571,7 @@ static void d3d10_gfx_unload_texture(void* data, uintptr_t handle) } #if 0 -static bool + static bool d3d10_get_hw_render_interface(void* data, const struct retro_hw_render_interface** iface) { d3d10_video_t* d3d10 = (d3d10_video_t*)data; diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index 66cdaf990c..405894bbef 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -55,7 +55,7 @@ static void d3d11_free_overlays(d3d11_video_t* d3d11) Release(d3d11->overlays.vbo); } -static void + static void d3d11_overlay_vertex_geom(void* data, unsigned index, float x, float y, float w, float h) { D3D11_MAPPED_SUBRESOURCE mapped_vbo; @@ -230,6 +230,7 @@ static void d3d11_set_filtering(void* data, unsigned index, bool smooth) static void d3d11_gfx_set_rotation(void* data, unsigned rotation) { math_matrix_4x4 rot; + D3D11_MAPPED_SUBRESOURCE mapped_ubo; d3d11_video_t* d3d11 = (d3d11_video_t*)data; if (!d3d11) @@ -238,7 +239,6 @@ static void d3d11_gfx_set_rotation(void* data, unsigned rotation) matrix_4x4_rotate_z(rot, rotation * (M_PI / 2.0f)); matrix_4x4_multiply(d3d11->mvp, rot, d3d11->ubo_values.mvp); - D3D11_MAPPED_SUBRESOURCE mapped_ubo; D3D11MapBuffer(d3d11->context, d3d11->frame.ubo, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo); *(math_matrix_4x4*)mapped_ubo.pData = d3d11->mvp; D3D11UnmapBuffer(d3d11->context, d3d11->frame.ubo, 0); @@ -258,7 +258,7 @@ static void d3d11_update_viewport(void* data, bool force_full) d3d11->frame.viewport.MaxDepth = 1.0f; if (d3d11->shader_preset && (d3d11->frame.output_size.x != d3d11->vp.width || - d3d11->frame.output_size.y != d3d11->vp.height)) + d3d11->frame.output_size.y != d3d11->vp.height)) d3d11->resize_render_targets = true; d3d11->frame.output_size.x = d3d11->vp.width; @@ -318,8 +318,9 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const { #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) unsigned i; - d3d11_texture_t* source; - d3d11_video_t* d3d11 = (d3d11_video_t*)data; + config_file_t* conf = NULL; + d3d11_texture_t* source = NULL; + d3d11_video_t* d3d11 = (d3d11_video_t*)data; if (!d3d11) return false; @@ -336,7 +337,7 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const return false; } - config_file_t* conf = config_file_new(path); + conf = config_file_new(path); if (!conf) return false; @@ -389,16 +390,16 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const /* clang-format on */ if (!slang_process( - d3d11->shader_preset, i, RARCH_SHADER_HLSL, 40, &semantics_map, - &d3d11->pass[i].semantics)) + d3d11->shader_preset, i, RARCH_SHADER_HLSL, 40, &semantics_map, + &d3d11->pass[i].semantics)) goto error; { static const D3D11_INPUT_ELEMENT_DESC desc[] = { { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d11_vertex_t, position), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d11_vertex_t, texcoord), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; #ifdef DEBUG bool save_hlsl = true; @@ -419,13 +420,13 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const strlcat(ps_path, ps_ext, sizeof(ps_path)); if (!d3d11_init_shader( - d3d11->device, vs_src, 0, vs_path, "main", NULL, NULL, desc, countof(desc), - &d3d11->pass[i].shader)) + d3d11->device, vs_src, 0, vs_path, "main", NULL, NULL, desc, countof(desc), + &d3d11->pass[i].shader)) save_hlsl = true; if (!d3d11_init_shader( - d3d11->device, ps_src, 0, ps_path, NULL, "main", NULL, NULL, 0, - &d3d11->pass[i].shader)) + d3d11->device, ps_src, 0, ps_path, NULL, "main", NULL, NULL, 0, + &d3d11->pass[i].shader)) save_hlsl = true; if (save_hlsl) @@ -552,24 +553,24 @@ static void d3d11_gfx_free(void* data) font_driver_free_osd(); - if (video_driver_is_video_cache_context()) - { + if (video_driver_is_video_cache_context()) + { cached_device_d3d11 = d3d11->device; - cached_context = d3d11->context; - cached_supportedFeatureLevel = d3d11->supportedFeatureLevel; - } - else - { - Release(d3d11->context); - Release(d3d11->device); - } + cached_context = d3d11->context; + cached_supportedFeatureLevel = d3d11->supportedFeatureLevel; + } + else + { + Release(d3d11->context); + Release(d3d11->device); + } win32_monitor_from_window(); win32_destroy_window(); free(d3d11); } -static void* + static void* d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** input_data) { unsigned i; @@ -609,12 +610,12 @@ d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** i UINT flags = 0; D3D_FEATURE_LEVEL requested_feature_levels[] = - { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - D3D_FEATURE_LEVEL_9_3 - }; + { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3 + }; DXGI_SWAP_CHAIN_DESC desc = { 0 }; UINT number_feature_levels = ARRAY_SIZE(requested_feature_levels); @@ -642,39 +643,39 @@ d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** i #ifdef DEBUG flags |= D3D11_CREATE_DEVICE_DEBUG; #endif - if(cached_device_d3d11 && cached_context) - { - IDXGIFactory* dxgiFactory = NULL; - IDXGIDevice* dxgiDevice = NULL; - IDXGIAdapter* adapter = NULL; + if(cached_device_d3d11 && cached_context) + { + IDXGIFactory* dxgiFactory = NULL; + IDXGIDevice* dxgiDevice = NULL; + IDXGIAdapter* adapter = NULL; - d3d11->device = cached_device_d3d11; - d3d11->context = cached_context; - d3d11->supportedFeatureLevel = cached_supportedFeatureLevel; + d3d11->device = cached_device_d3d11; + d3d11->context = cached_context; + d3d11->supportedFeatureLevel = cached_supportedFeatureLevel; - d3d11->device->lpVtbl->QueryInterface( + d3d11->device->lpVtbl->QueryInterface( d3d11->device, uuidof(IDXGIDevice), (void**)&dxgiDevice); - dxgiDevice->lpVtbl->GetAdapter(dxgiDevice, &adapter); - adapter->lpVtbl->GetParent( + dxgiDevice->lpVtbl->GetAdapter(dxgiDevice, &adapter); + adapter->lpVtbl->GetParent( adapter, uuidof(IDXGIFactory1), (void**)&dxgiFactory); - dxgiFactory->lpVtbl->CreateSwapChain( + dxgiFactory->lpVtbl->CreateSwapChain( dxgiFactory, (IUnknown*)d3d11->device, &desc, (IDXGISwapChain**)&d3d11->swapChain); - dxgiFactory->lpVtbl->Release(dxgiFactory); - adapter->lpVtbl->Release(adapter); - dxgiDevice->lpVtbl->Release(dxgiDevice); - } - else - { - if (FAILED(D3D11CreateDeviceAndSwapChain( - NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, - requested_feature_levels, number_feature_levels, - D3D11_SDK_VERSION, &desc, - (IDXGISwapChain**)&d3d11->swapChain, &d3d11->device, - &d3d11->supportedFeatureLevel, &d3d11->context))) + dxgiFactory->lpVtbl->Release(dxgiFactory); + adapter->lpVtbl->Release(adapter); + dxgiDevice->lpVtbl->Release(dxgiDevice); + } + else + { + if (FAILED(D3D11CreateDeviceAndSwapChain( + NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, + requested_feature_levels, number_feature_levels, + D3D11_SDK_VERSION, &desc, + (IDXGISwapChain**)&d3d11->swapChain, &d3d11->device, + &d3d11->supportedFeatureLevel, &d3d11->context))) goto error; - } + } } { @@ -801,52 +802,52 @@ d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** i { D3D11_INPUT_ELEMENT_DESC desc[] = { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d11_vertex_t, position), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d11_vertex_t, texcoord), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d11_vertex_t, color), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; static const char shader[] = #include "d3d_shaders/opaque_sm5.hlsl.h" - ; + ; if (!d3d11_init_shader( - d3d11->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", NULL, desc, - countof(desc), &d3d11->shaders[VIDEO_SHADER_STOCK_BLEND])) + d3d11->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", NULL, desc, + countof(desc), &d3d11->shaders[VIDEO_SHADER_STOCK_BLEND])) goto error; } { D3D11_INPUT_ELEMENT_DESC desc[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d11_sprite_t, pos), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d11_sprite_t, coords), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d11_sprite_t, colors[0]), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d11_sprite_t, colors[1]), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 2, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d11_sprite_t, colors[2]), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 3, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d11_sprite_t, colors[3]), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "PARAMS", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d11_sprite_t, params), - D3D11_INPUT_PER_VERTEX_DATA, 0 }, + D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; static const char shader[] = #include "d3d_shaders/sprite_sm4.hlsl.h" - ; + ; if (!d3d11_init_shader( - d3d11->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", "GSMain", desc, - countof(desc), &d3d11->sprites.shader)) + d3d11->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", "GSMain", desc, + countof(desc), &d3d11->sprites.shader)) goto error; if (!d3d11_init_shader( - d3d11->device, shader, sizeof(shader), NULL, "VSMain", "PSMainA8", "GSMain", desc, - countof(desc), &d3d11->sprites.shader_font)) + d3d11->device, shader, sizeof(shader), NULL, "VSMain", "PSMainA8", "GSMain", desc, + countof(desc), &d3d11->sprites.shader_font)) goto error; } @@ -960,7 +961,7 @@ d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** i } if (video_driver_get_hw_context()->context_type == RETRO_HW_CONTEXT_DIRECT3D && - video_driver_get_hw_context()->version_major == 11) + video_driver_get_hw_context()->version_major == 11) { d3d11->hw.enable = true; d3d11->hw.iface.interface_type = RETRO_HW_RENDER_INTERFACE_D3D11; @@ -1064,7 +1065,7 @@ static void d3d11_init_render_targets(d3d11_video_t* d3d11, unsigned width, unsi RARCH_LOG("[D3D11]: Updating framebuffer size %u x %u.\n", width, height); if ((i != (d3d11->shader_preset->passes - 1)) || (width != d3d11->vp.width) || - (height != d3d11->vp.height)) + (height != d3d11->vp.height)) { d3d11->pass[i].viewport.Width = width; d3d11->pass[i].viewport.Height = height; @@ -1145,7 +1146,7 @@ static bool d3d11_gfx_frame( #if 0 /* custom viewport doesn't call apply_state_changes, so we can't rely on this for now */ if (d3d11->resize_viewport) #endif - d3d11_update_viewport(d3d11, false); + d3d11_update_viewport(d3d11, false); D3D11SetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); @@ -1160,7 +1161,7 @@ static bool d3d11_gfx_frame( if (d3d11->shader_preset) { if (d3d11->frame.texture[0].desc.Width != width || - d3d11->frame.texture[0].desc.Height != height) + d3d11->frame.texture[0].desc.Height != height) d3d11->resize_render_targets = true; if (d3d11->resize_render_targets) @@ -1194,7 +1195,7 @@ static bool d3d11_gfx_frame( /* either no history, or we moved a texture of a different size in the front slot */ if (d3d11->frame.texture[0].desc.Width != width || - d3d11->frame.texture[0].desc.Height != height) + d3d11->frame.texture[0].desc.Height != height) { d3d11->frame.texture[0].desc.Width = width; d3d11->frame.texture[0].desc.Height = height; @@ -1234,7 +1235,7 @@ static bool d3d11_gfx_frame( if (d3d11->shader_preset->pass[i].frame_count_mod) d3d11->pass[i].frame_count = - frame_count % d3d11->shader_preset->pass[i].frame_count_mod; + frame_count % d3d11->shader_preset->pass[i].frame_count_mod; else d3d11->pass[i].frame_count = frame_count; @@ -1596,7 +1597,7 @@ static void d3d11_gfx_unload_texture(void* data, uintptr_t handle) free(texture); } -static bool + static bool d3d11_get_hw_render_interface(void* data, const struct retro_hw_render_interface** iface) { d3d11_video_t* d3d11 = (d3d11_video_t*)data; diff --git a/menu/drivers_display/menu_display_d3d10.c b/menu/drivers_display/menu_display_d3d10.c index 234524d1ca..6bc9079c41 100644 --- a/menu/drivers_display/menu_display_d3d10.c +++ b/menu/drivers_display/menu_display_d3d10.c @@ -208,8 +208,10 @@ static void menu_display_d3d10_draw_pipeline(menu_display_ctx_draw_t* draw, desc.ByteWidth = ca->coords.vertices * 2 * sizeof(float); desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; - D3D10_SUBRESOURCE_DATA vertexData = { ca->coords.vertex }; - D3D10CreateBuffer(d3d10->device, &desc, &vertexData, &d3d10->menu_pipeline_vbo); + { + D3D10_SUBRESOURCE_DATA vertexData = { ca->coords.vertex }; + D3D10CreateBuffer(d3d10->device, &desc, &vertexData, &d3d10->menu_pipeline_vbo); + } } D3D10SetVertexBuffer(d3d10->device, 0, d3d10->menu_pipeline_vbo, 2 * sizeof(float), 0); draw->coords->vertices = ca->coords.vertices; diff --git a/menu/drivers_display/menu_display_d3d11.c b/menu/drivers_display/menu_display_d3d11.c index ce68977fce..2e579cb49b 100644 --- a/menu/drivers_display/menu_display_d3d11.c +++ b/menu/drivers_display/menu_display_d3d11.c @@ -207,8 +207,10 @@ static void menu_display_d3d11_draw_pipeline(menu_display_ctx_draw_t *draw, desc.ByteWidth = ca->coords.vertices * 2 * sizeof(float); desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - D3D11_SUBRESOURCE_DATA vertexData = { ca->coords.vertex }; - D3D11CreateBuffer(d3d11->device, &desc, &vertexData, &d3d11->menu_pipeline_vbo); + { + D3D11_SUBRESOURCE_DATA vertexData = { ca->coords.vertex }; + D3D11CreateBuffer(d3d11->device, &desc, &vertexData, &d3d11->menu_pipeline_vbo); + } } D3D11SetVertexBuffer(d3d11->context, 0, d3d11->menu_pipeline_vbo, 2 * sizeof(float), 0); draw->coords->vertices = ca->coords.vertices; diff --git a/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj b/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj index 20cac85fed..4c99b8fef5 100644 --- a/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj +++ b/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj @@ -52,7 +52,8 @@ Level3 Disabled - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + WIN32;WANT_GLSLANG;HAVE_DYNAMIC;HAVE_DYLIB;HAVE_SPIRV_CROSS;HAVE_MENU;HAVE_SLANG;HAVE_GLSLANG;HAVE_UPDATE_ASSETS;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_RGUI;HAVE_MATERIALUI;NDEBUG;_WINDOWS;HAVE_XAUDIO;HAVE_DSOUND;HAVE_DINPUT;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_OPENGL;HAVE_VULKAN;HAVE_GLSL;HAVE_THREADS;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_RJPEG;HAVE_RPNG;HAVE_ZLIB;WANT_ZLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_OVERLAY;HAVE_7ZIP;HAVE_LIBRETRODB;HAVE_STB_FONT;_DEBUG;%(PreprocessorDefinitions) + $(SolutionDir)\..\..\deps;$(SolutionDir)\..\..\gfx\include;$(SolutionDir)\..\..\gfx\include\dxsdk;$(SolutionDir)\..\..\libretro-common\include;$(SolutionDir)\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) Windows @@ -67,7 +68,8 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + WIN32;WANT_GLSLANG;HAVE_DYNAMIC;HAVE_DYLIB;HAVE_SPIRV_CROSS;HAVE_MENU;HAVE_SLANG;HAVE_GLSLANG;HAVE_UPDATE_ASSETS;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_RGUI;HAVE_MATERIALUI;NDEBUG;_WINDOWS;HAVE_XAUDIO;HAVE_DSOUND;HAVE_DINPUT;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_OPENGL;HAVE_VULKAN;HAVE_GLSL;HAVE_THREADS;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_RJPEG;HAVE_RPNG;HAVE_ZLIB;WANT_ZLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_OVERLAY;HAVE_7ZIP;HAVE_LIBRETRODB;HAVE_STB_FONT;%(PreprocessorDefinitions) + $(SolutionDir)\..\..\deps;$(SolutionDir)\..\..\gfx\include;$(SolutionDir)\..\..\gfx\include\dxsdk;$(SolutionDir)\..\..\libretro-common\include;$(SolutionDir)\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) Windows From 4a54826d9b9d3a990b9753b3a1860b4187eedc8e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 21:14:56 +0200 Subject: [PATCH 050/182] Remove unused variable --- gfx/common/vulkan_common.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 8a38a4855c..a736a8c134 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -2372,8 +2372,6 @@ void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index) void vulkan_context_destroy(gfx_ctx_vulkan_data_t *vk, bool destroy_surface) { - unsigned i; - if (!vk->context.instance) return; From b28af7734f6d73cfd50e652d9c7344f9f6e3ddc1 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 21:18:37 +0200 Subject: [PATCH 051/182] MSVC 2012 solution works now --- pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj b/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj index 4c99b8fef5..c4ae7da5b0 100644 --- a/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj +++ b/pkg/msvc/msvc-2012/RetroArch-msvc2012.vcxproj @@ -52,12 +52,14 @@ Level3 Disabled - WIN32;WANT_GLSLANG;HAVE_DYNAMIC;HAVE_DYLIB;HAVE_SPIRV_CROSS;HAVE_MENU;HAVE_SLANG;HAVE_GLSLANG;HAVE_UPDATE_ASSETS;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_RGUI;HAVE_MATERIALUI;NDEBUG;_WINDOWS;HAVE_XAUDIO;HAVE_DSOUND;HAVE_DINPUT;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_OPENGL;HAVE_VULKAN;HAVE_GLSL;HAVE_THREADS;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_RJPEG;HAVE_RPNG;HAVE_ZLIB;WANT_ZLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_OVERLAY;HAVE_7ZIP;HAVE_LIBRETRODB;HAVE_STB_FONT;_DEBUG;%(PreprocessorDefinitions) + WIN32;HAVE_DYNAMIC;HAVE_DYLIB;HAVE_MENU;HAVE_UPDATE_ASSETS;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_RGUI;HAVE_MATERIALUI;NDEBUG;_WINDOWS;HAVE_XAUDIO;HAVE_DSOUND;HAVE_DINPUT;HAVE_D3D;HAVE_D3D9;HAVE_OPENGL;HAVE_GLSL;HAVE_THREADS;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_RJPEG;HAVE_RPNG;HAVE_ZLIB;WANT_ZLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_OVERLAY;HAVE_7ZIP;HAVE_LIBRETRODB;HAVE_STB_FONT;_DEBUG;%(PreprocessorDefinitions) $(SolutionDir)\..\..\deps;$(SolutionDir)\..\..\gfx\include;$(SolutionDir)\..\..\gfx\include\dxsdk;$(SolutionDir)\..\..\libretro-common\include;$(SolutionDir)\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) Windows true + mainCRTStartup + Iphlpapi.lib;%(AdditionalDependencies) @@ -68,7 +70,7 @@ MaxSpeed true true - WIN32;WANT_GLSLANG;HAVE_DYNAMIC;HAVE_DYLIB;HAVE_SPIRV_CROSS;HAVE_MENU;HAVE_SLANG;HAVE_GLSLANG;HAVE_UPDATE_ASSETS;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_RGUI;HAVE_MATERIALUI;NDEBUG;_WINDOWS;HAVE_XAUDIO;HAVE_DSOUND;HAVE_DINPUT;HAVE_D3D;HAVE_D3D9;HAVE_D3D10;HAVE_D3D11;HAVE_OPENGL;HAVE_VULKAN;HAVE_GLSL;HAVE_THREADS;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_RJPEG;HAVE_RPNG;HAVE_ZLIB;WANT_ZLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_OVERLAY;HAVE_7ZIP;HAVE_LIBRETRODB;HAVE_STB_FONT;%(PreprocessorDefinitions) + WIN32;HAVE_DYNAMIC;HAVE_DYLIB;HAVE_MENU;HAVE_UPDATE_ASSETS;HAVE_XMB;HAVE_SHADERPIPELINE;HAVE_RGUI;HAVE_MATERIALUI;NDEBUG;_WINDOWS;HAVE_XAUDIO;HAVE_DSOUND;HAVE_DINPUT;HAVE_D3D;HAVE_D3D9;HAVE_OPENGL;HAVE_GLSL;HAVE_THREADS;RARCH_INTERNAL;HAVE_CC_RESAMPLER;HAVE_RUNAHEAD;HAVE_GRIFFIN;HAVE_RJPEG;HAVE_RPNG;HAVE_ZLIB;WANT_ZLIB;HAVE_NETWORKING;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_OVERLAY;HAVE_7ZIP;HAVE_LIBRETRODB;HAVE_STB_FONT;%(PreprocessorDefinitions) $(SolutionDir)\..\..\deps;$(SolutionDir)\..\..\gfx\include;$(SolutionDir)\..\..\gfx\include\dxsdk;$(SolutionDir)\..\..\libretro-common\include;$(SolutionDir)\..\..\deps\SPIRV-Cross;%(AdditionalIncludeDirectories) @@ -76,6 +78,8 @@ true true true + mainCRTStartup + Iphlpapi.lib;%(AdditionalDependencies) From 35991f5feb28413d0c2fdd98cd232ec5142909f9 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 21:32:14 +0200 Subject: [PATCH 052/182] Don't use == NULL --- managers/cheat_manager.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/managers/cheat_manager.c b/managers/cheat_manager.c index 81ccdc64ba..df087cab82 100644 --- a/managers/cheat_manager.c +++ b/managers/cheat_manager.c @@ -593,7 +593,7 @@ bool cheat_manager_get_game_specific_filename(char * cheat_filename, size_t max_ const char *game_name = NULL; struct retro_system_info system_info; - if ( settings == NULL || global == NULL || cheat_filename == NULL) + if (!settings || !global || !cheat_filename) return false ; if ( !core_get_system_info(&system_info) ) @@ -813,7 +813,7 @@ int cheat_manager_search(enum cheat_search_type search_type) unsigned int bits = 8 ; bool refresh = false; - if ( cheat_manager_state.curr_memory_buf == NULL ) + if (!cheat_manager_state.curr_memory_buf) { runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_NOT_INITIALIZED), 1, 180, true); return 0 ; @@ -1290,8 +1290,8 @@ void cheat_manager_match_action(enum cheat_match_action_type match_action, unsig if (target_match_idx > cheat_manager_state.num_matches-1) return; - if (curr == NULL ) - return ; + if (!curr) + return; cheat_manager_setup_search_meta(cheat_manager_state.search_bit_size, &bytes_per_item, &mask, &bits); From f9e87374763f29d330f1b8a35b2d4864437470d2 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 21:34:20 +0200 Subject: [PATCH 053/182] Remove libui - we don't need it anymore now that we have the Qt desktop UI --- Makefile.common | 153 --- command.c | 6 - command.h | 3 +- deps/libui/LICENSE | 9 - deps/libui/common/CMakeLists.txt | 16 - deps/libui/common/areaevents.c | 167 ---- deps/libui/common/control.c | 101 -- deps/libui/common/controlsigs.h | 25 - deps/libui/common/debug.c | 21 - deps/libui/common/matrix.c | 50 - deps/libui/common/shouldquit.c | 22 - deps/libui/common/uipriv.h | 58 -- deps/libui/common/userbugs.c | 8 - deps/libui/darwin/CMakeLists.txt | 79 -- deps/libui/darwin/alloc.m | 89 -- deps/libui/darwin/area.m | 475 --------- deps/libui/darwin/areaevents.m | 159 --- deps/libui/darwin/autolayout.m | 161 --- deps/libui/darwin/box.m | 469 --------- deps/libui/darwin/button.m | 113 --- deps/libui/darwin/checkbox.m | 129 --- deps/libui/darwin/colorbutton.m | 159 --- deps/libui/darwin/combobox.m | 145 --- deps/libui/darwin/control.m | 84 -- deps/libui/darwin/datetimepicker.m | 42 - deps/libui/darwin/debug.m | 19 - deps/libui/darwin/draw.m | 454 --------- deps/libui/darwin/drawtext.m | 655 ------------ deps/libui/darwin/editablecombo.m | 185 ---- deps/libui/darwin/entry.m | 251 ----- deps/libui/darwin/fontbutton.m | 218 ---- deps/libui/darwin/form.m | 561 ----------- deps/libui/darwin/grid.m | 800 --------------- deps/libui/darwin/group.m | 194 ---- deps/libui/darwin/image.m | 82 -- deps/libui/darwin/label.m | 43 - deps/libui/darwin/main.m | 239 ----- deps/libui/darwin/map.m | 59 -- deps/libui/darwin/menu.m | 368 ------- deps/libui/darwin/multilineentry.m | 233 ----- deps/libui/darwin/progressbar.m | 78 -- deps/libui/darwin/radiobuttons.m | 207 ---- deps/libui/darwin/scrollview.m | 61 -- deps/libui/darwin/separator.m | 45 - deps/libui/darwin/slider.m | 147 --- deps/libui/darwin/spinbox.m | 214 ---- deps/libui/darwin/stddialogs.m | 123 --- deps/libui/darwin/tab.m | 292 ------ deps/libui/darwin/text.m | 19 - deps/libui/darwin/uipriv_darwin.h | 146 --- deps/libui/darwin/util.m | 15 - deps/libui/darwin/window.m | 407 -------- deps/libui/darwin/winmoveresize.m | 253 ----- deps/libui/libui_main.c | 543 ---------- deps/libui/ui.h | 691 ------------- deps/libui/ui_darwin.h | 224 ----- deps/libui/ui_unix.h | 140 --- deps/libui/ui_windows.h | 267 ----- deps/libui/unix/CMakeLists.txt | 85 -- deps/libui/unix/alloc.c | 84 -- deps/libui/unix/area.c | 633 ------------ deps/libui/unix/box.c | 159 --- deps/libui/unix/button.c | 55 -- deps/libui/unix/cellrendererbutton.c | 299 ------ deps/libui/unix/checkbox.c | 78 -- deps/libui/unix/child.c | 120 --- deps/libui/unix/colorbutton.c | 80 -- deps/libui/unix/combobox.c | 66 -- deps/libui/unix/control.c | 14 - deps/libui/unix/datetimepicker.c | 599 ----------- deps/libui/unix/debug.c | 14 - deps/libui/unix/draw.c | 141 --- deps/libui/unix/draw.h | 13 - deps/libui/unix/drawmatrix.c | 109 -- deps/libui/unix/drawpath.c | 199 ---- deps/libui/unix/drawtext.c | 293 ------ deps/libui/unix/editablecombo.c | 79 -- deps/libui/unix/entry.c | 97 -- deps/libui/unix/fontbutton.c | 70 -- deps/libui/unix/form.c | 159 --- deps/libui/unix/future.c | 42 - deps/libui/unix/graphemes.c | 31 - deps/libui/unix/grid.c | 141 --- deps/libui/unix/group.c | 89 -- deps/libui/unix/image.c | 120 --- deps/libui/unix/label.c | 36 - deps/libui/unix/main.c | 108 -- deps/libui/unix/menu.c | 366 ------- deps/libui/unix/multilineentry.c | 124 --- deps/libui/unix/progressbar.c | 71 -- deps/libui/unix/radiobuttons.c | 121 --- deps/libui/unix/separator.c | 34 - deps/libui/unix/slider.c | 71 -- deps/libui/unix/spinbox.c | 72 -- deps/libui/unix/stddialogs.c | 66 -- deps/libui/unix/tab.c | 97 -- deps/libui/unix/text.c | 12 - deps/libui/unix/uipriv_unix.h | 65 -- deps/libui/unix/util.c | 10 - deps/libui/unix/window.c | 279 ------ deps/libui/windows/CMakeLists.txt | 91 -- deps/libui/windows/_uipriv_migrate.hpp | 61 -- deps/libui/windows/alloc.cpp | 63 -- deps/libui/windows/area.cpp | 206 ---- deps/libui/windows/area.hpp | 45 - deps/libui/windows/areadraw.cpp | 137 --- deps/libui/windows/areaevents.cpp | 421 -------- deps/libui/windows/areascroll.cpp | 247 ----- deps/libui/windows/areautil.cpp | 37 - deps/libui/windows/box.cpp | 320 ------ deps/libui/windows/button.cpp | 104 -- deps/libui/windows/checkbox.cpp | 117 --- deps/libui/windows/colorbutton.cpp | 192 ---- deps/libui/windows/colordialog.cpp | 1264 ------------------------ deps/libui/windows/combobox.cpp | 110 --- deps/libui/windows/compilerver.hpp | 13 - deps/libui/windows/container.cpp | 110 --- deps/libui/windows/control.cpp | 121 --- deps/libui/windows/d2dscratch.cpp | 166 ---- deps/libui/windows/datetimepicker.cpp | 191 ---- deps/libui/windows/debug.cpp | 84 -- deps/libui/windows/draw.cpp | 511 ---------- deps/libui/windows/draw.hpp | 16 - deps/libui/windows/drawmatrix.cpp | 117 --- deps/libui/windows/drawpath.cpp | 246 ----- deps/libui/windows/drawtext.cpp | 531 ---------- deps/libui/windows/dwrite.cpp | 88 -- deps/libui/windows/editablecombo.cpp | 115 --- deps/libui/windows/entry.cpp | 134 --- deps/libui/windows/events.cpp | 151 --- deps/libui/windows/fontbutton.cpp | 122 --- deps/libui/windows/fontdialog.cpp | 686 ------------- deps/libui/windows/form.cpp | 319 ------ deps/libui/windows/graphemes.cpp | 80 -- deps/libui/windows/grid.cpp | 658 ------------ deps/libui/windows/group.cpp | 217 ---- deps/libui/windows/init.cpp | 167 ---- deps/libui/windows/label.cpp | 57 -- deps/libui/windows/libui.manifest | 31 - deps/libui/windows/main.cpp | 130 --- deps/libui/windows/menu.cpp | 369 ------- deps/libui/windows/multilineentry.cpp | 152 --- deps/libui/windows/notes | 3 - deps/libui/windows/parent.cpp | 144 --- deps/libui/windows/progressbar.cpp | 83 -- deps/libui/windows/radiobuttons.cpp | 196 ---- deps/libui/windows/resources.hpp | 37 - deps/libui/windows/resources.rc | 96 -- deps/libui/windows/separator.cpp | 69 -- deps/libui/windows/sizing.cpp | 62 -- deps/libui/windows/slider.cpp | 98 -- deps/libui/windows/spinbox.cpp | 215 ---- deps/libui/windows/stddialogs.cpp | 133 --- deps/libui/windows/tab.cpp | 287 ------ deps/libui/windows/tabpage.cpp | 131 --- deps/libui/windows/text.cpp | 107 -- deps/libui/windows/uipriv_windows.hpp | 164 --- deps/libui/windows/utf16.cpp | 153 --- deps/libui/windows/utilwin.cpp | 76 -- deps/libui/windows/winapi.hpp | 51 - deps/libui/windows/window.cpp | 533 ---------- deps/libui/windows/winpublic.cpp | 61 -- deps/libui/windows/winutil.cpp | 154 --- retroarch.c | 4 - 164 files changed, 1 insertion(+), 28230 deletions(-) delete mode 100644 deps/libui/LICENSE delete mode 100644 deps/libui/common/CMakeLists.txt delete mode 100644 deps/libui/common/areaevents.c delete mode 100644 deps/libui/common/control.c delete mode 100644 deps/libui/common/controlsigs.h delete mode 100644 deps/libui/common/debug.c delete mode 100644 deps/libui/common/matrix.c delete mode 100644 deps/libui/common/shouldquit.c delete mode 100644 deps/libui/common/uipriv.h delete mode 100644 deps/libui/common/userbugs.c delete mode 100644 deps/libui/darwin/CMakeLists.txt delete mode 100644 deps/libui/darwin/alloc.m delete mode 100644 deps/libui/darwin/area.m delete mode 100644 deps/libui/darwin/areaevents.m delete mode 100644 deps/libui/darwin/autolayout.m delete mode 100644 deps/libui/darwin/box.m delete mode 100644 deps/libui/darwin/button.m delete mode 100644 deps/libui/darwin/checkbox.m delete mode 100644 deps/libui/darwin/colorbutton.m delete mode 100644 deps/libui/darwin/combobox.m delete mode 100644 deps/libui/darwin/control.m delete mode 100644 deps/libui/darwin/datetimepicker.m delete mode 100644 deps/libui/darwin/debug.m delete mode 100644 deps/libui/darwin/draw.m delete mode 100644 deps/libui/darwin/drawtext.m delete mode 100644 deps/libui/darwin/editablecombo.m delete mode 100644 deps/libui/darwin/entry.m delete mode 100644 deps/libui/darwin/fontbutton.m delete mode 100644 deps/libui/darwin/form.m delete mode 100644 deps/libui/darwin/grid.m delete mode 100644 deps/libui/darwin/group.m delete mode 100644 deps/libui/darwin/image.m delete mode 100644 deps/libui/darwin/label.m delete mode 100644 deps/libui/darwin/main.m delete mode 100644 deps/libui/darwin/map.m delete mode 100644 deps/libui/darwin/menu.m delete mode 100644 deps/libui/darwin/multilineentry.m delete mode 100644 deps/libui/darwin/progressbar.m delete mode 100644 deps/libui/darwin/radiobuttons.m delete mode 100644 deps/libui/darwin/scrollview.m delete mode 100644 deps/libui/darwin/separator.m delete mode 100644 deps/libui/darwin/slider.m delete mode 100644 deps/libui/darwin/spinbox.m delete mode 100644 deps/libui/darwin/stddialogs.m delete mode 100644 deps/libui/darwin/tab.m delete mode 100644 deps/libui/darwin/text.m delete mode 100644 deps/libui/darwin/uipriv_darwin.h delete mode 100644 deps/libui/darwin/util.m delete mode 100644 deps/libui/darwin/window.m delete mode 100644 deps/libui/darwin/winmoveresize.m delete mode 100644 deps/libui/libui_main.c delete mode 100644 deps/libui/ui.h delete mode 100644 deps/libui/ui_darwin.h delete mode 100644 deps/libui/ui_unix.h delete mode 100644 deps/libui/ui_windows.h delete mode 100644 deps/libui/unix/CMakeLists.txt delete mode 100644 deps/libui/unix/alloc.c delete mode 100644 deps/libui/unix/area.c delete mode 100644 deps/libui/unix/box.c delete mode 100644 deps/libui/unix/button.c delete mode 100644 deps/libui/unix/cellrendererbutton.c delete mode 100644 deps/libui/unix/checkbox.c delete mode 100644 deps/libui/unix/child.c delete mode 100644 deps/libui/unix/colorbutton.c delete mode 100644 deps/libui/unix/combobox.c delete mode 100644 deps/libui/unix/control.c delete mode 100644 deps/libui/unix/datetimepicker.c delete mode 100644 deps/libui/unix/debug.c delete mode 100644 deps/libui/unix/draw.c delete mode 100644 deps/libui/unix/draw.h delete mode 100644 deps/libui/unix/drawmatrix.c delete mode 100644 deps/libui/unix/drawpath.c delete mode 100644 deps/libui/unix/drawtext.c delete mode 100644 deps/libui/unix/editablecombo.c delete mode 100644 deps/libui/unix/entry.c delete mode 100644 deps/libui/unix/fontbutton.c delete mode 100644 deps/libui/unix/form.c delete mode 100644 deps/libui/unix/future.c delete mode 100644 deps/libui/unix/graphemes.c delete mode 100644 deps/libui/unix/grid.c delete mode 100644 deps/libui/unix/group.c delete mode 100644 deps/libui/unix/image.c delete mode 100644 deps/libui/unix/label.c delete mode 100644 deps/libui/unix/main.c delete mode 100644 deps/libui/unix/menu.c delete mode 100644 deps/libui/unix/multilineentry.c delete mode 100644 deps/libui/unix/progressbar.c delete mode 100644 deps/libui/unix/radiobuttons.c delete mode 100644 deps/libui/unix/separator.c delete mode 100644 deps/libui/unix/slider.c delete mode 100644 deps/libui/unix/spinbox.c delete mode 100644 deps/libui/unix/stddialogs.c delete mode 100644 deps/libui/unix/tab.c delete mode 100644 deps/libui/unix/text.c delete mode 100644 deps/libui/unix/uipriv_unix.h delete mode 100644 deps/libui/unix/util.c delete mode 100644 deps/libui/unix/window.c delete mode 100644 deps/libui/windows/CMakeLists.txt delete mode 100644 deps/libui/windows/_uipriv_migrate.hpp delete mode 100644 deps/libui/windows/alloc.cpp delete mode 100644 deps/libui/windows/area.cpp delete mode 100644 deps/libui/windows/area.hpp delete mode 100644 deps/libui/windows/areadraw.cpp delete mode 100644 deps/libui/windows/areaevents.cpp delete mode 100644 deps/libui/windows/areascroll.cpp delete mode 100644 deps/libui/windows/areautil.cpp delete mode 100644 deps/libui/windows/box.cpp delete mode 100644 deps/libui/windows/button.cpp delete mode 100644 deps/libui/windows/checkbox.cpp delete mode 100644 deps/libui/windows/colorbutton.cpp delete mode 100644 deps/libui/windows/colordialog.cpp delete mode 100644 deps/libui/windows/combobox.cpp delete mode 100644 deps/libui/windows/compilerver.hpp delete mode 100644 deps/libui/windows/container.cpp delete mode 100644 deps/libui/windows/control.cpp delete mode 100644 deps/libui/windows/d2dscratch.cpp delete mode 100644 deps/libui/windows/datetimepicker.cpp delete mode 100644 deps/libui/windows/debug.cpp delete mode 100644 deps/libui/windows/draw.cpp delete mode 100644 deps/libui/windows/draw.hpp delete mode 100644 deps/libui/windows/drawmatrix.cpp delete mode 100644 deps/libui/windows/drawpath.cpp delete mode 100644 deps/libui/windows/drawtext.cpp delete mode 100644 deps/libui/windows/dwrite.cpp delete mode 100644 deps/libui/windows/editablecombo.cpp delete mode 100644 deps/libui/windows/entry.cpp delete mode 100644 deps/libui/windows/events.cpp delete mode 100644 deps/libui/windows/fontbutton.cpp delete mode 100644 deps/libui/windows/fontdialog.cpp delete mode 100644 deps/libui/windows/form.cpp delete mode 100644 deps/libui/windows/graphemes.cpp delete mode 100644 deps/libui/windows/grid.cpp delete mode 100644 deps/libui/windows/group.cpp delete mode 100644 deps/libui/windows/init.cpp delete mode 100644 deps/libui/windows/label.cpp delete mode 100644 deps/libui/windows/libui.manifest delete mode 100644 deps/libui/windows/main.cpp delete mode 100644 deps/libui/windows/menu.cpp delete mode 100644 deps/libui/windows/multilineentry.cpp delete mode 100644 deps/libui/windows/notes delete mode 100644 deps/libui/windows/parent.cpp delete mode 100644 deps/libui/windows/progressbar.cpp delete mode 100644 deps/libui/windows/radiobuttons.cpp delete mode 100644 deps/libui/windows/resources.hpp delete mode 100644 deps/libui/windows/resources.rc delete mode 100644 deps/libui/windows/separator.cpp delete mode 100644 deps/libui/windows/sizing.cpp delete mode 100644 deps/libui/windows/slider.cpp delete mode 100644 deps/libui/windows/spinbox.cpp delete mode 100644 deps/libui/windows/stddialogs.cpp delete mode 100644 deps/libui/windows/tab.cpp delete mode 100644 deps/libui/windows/tabpage.cpp delete mode 100644 deps/libui/windows/text.cpp delete mode 100644 deps/libui/windows/uipriv_windows.hpp delete mode 100644 deps/libui/windows/utf16.cpp delete mode 100644 deps/libui/windows/utilwin.cpp delete mode 100644 deps/libui/windows/winapi.hpp delete mode 100644 deps/libui/windows/window.cpp delete mode 100644 deps/libui/windows/winpublic.cpp delete mode 100644 deps/libui/windows/winutil.cpp diff --git a/Makefile.common b/Makefile.common index 7799e67183..27a86a6d1c 100644 --- a/Makefile.common +++ b/Makefile.common @@ -374,7 +374,6 @@ OBJ += libretro-db/bintree.o \ endif ifneq ($(C89_BUILD), 1) -HAVE_LIBUI = 0 HAVE_GTKPLUS = 0 ifeq ($(HAVE_SSL), 1) @@ -464,158 +463,6 @@ OBJS_TLS = deps/mbedtls/debug.o \ OBJ += $(OBJS_TLS_CRYPTO) $(OBJS_TLS_X509) $(OBJS_TLS) endif -ifeq ($(HAVE_LIBUI), 1) -DEFINES += -DHAVE_LIBUI -ifneq ($(findstring Win32,$(OS)),) -OBJ += deps/libui/windows/alloc.o \ - deps/libui/windows/area.o \ - deps/libui/windows/areadraw.o \ - deps/libui/windows/areaevents.o \ - deps/libui/windows/areascroll.o \ - deps/libui/windows/areautil.o \ - deps/libui/windows/box.o \ - deps/libui/windows/button.o \ - deps/libui/windows/checkbox.o \ - deps/libui/windows/colorbutton.o \ - deps/libui/windows/colordialog.o \ - deps/libui/windows/combobox.o \ - deps/libui/windows/container.o \ - deps/libui/windows/control.o \ - deps/libui/windows/d2dscratch.o \ - deps/libui/windows/datetimepicker.o \ - deps/libui/windows/debug.o \ - deps/libui/windows/draw.o \ - deps/libui/windows/drawmatrix.o \ - deps/libui/windows/drawpath.o \ - deps/libui/windows/drawtext.o \ - deps/libui/windows/dwrite.o \ - deps/libui/windows/editablecombo.o \ - deps/libui/windows/entry.o \ - deps/libui/windows/events.o \ - deps/libui/windows/fontbutton.o \ - deps/libui/windows/fontdialog.o \ - deps/libui/windows/form.o \ - deps/libui/windows/graphemes.o \ - deps/libui/windows/grid.o \ - deps/libui/windows/group.o \ - deps/libui/windows/init.o \ - deps/libui/windows/label.o \ - deps/libui/windows/main.o \ - deps/libui/windows/menu.o \ - deps/libui/windows/multilineentry.o \ - deps/libui/windows/parent.o \ - deps/libui/windows/progressbar.o \ - deps/libui/windows/radiobuttons.o \ - deps/libui/windows/separator.o \ - deps/libui/windows/sizing.o \ - deps/libui/windows/slider.o \ - deps/libui/windows/spinbox.o \ - deps/libui/windows/stddialogs.o \ - deps/libui/windows/tab.o \ - deps/libui/windows/tabpage.o \ - deps/libui/windows/text.o \ - deps/libui/windows/utf16.o \ - deps/libui/windows/utilwin.o \ - deps/libui/windows/window.o \ - deps/libui/windows/winpublic.o \ - deps/libui/windows/winutil.o -LIBS += -luxtheme -ld2d1 -ldwrite -lusp10 -else -ifneq ($(findstring Darwin,$(OS)),) -OBJ += deps/libui/darwin/alloc.o \ - deps/libui/darwin/area.o \ - deps/libui/darwin/areaevents.o \ - deps/libui/darwin/autolayout.o \ - deps/libui/darwin/box.o \ - deps/libui/darwin/button.o \ - deps/libui/darwin/checkbox.o \ - deps/libui/darwin/colorbutton.o \ - deps/libui/darwin/combobox.o \ - deps/libui/darwin/control.o \ - deps/libui/darwin/datetimepicker.o \ - deps/libui/darwin/debug.o \ - deps/libui/darwin/draw.o \ - deps/libui/darwin/drawtext.o \ - deps/libui/darwin/editablecombo.o \ - deps/libui/darwin/entry.o \ - deps/libui/darwin/fontbutton.o \ - deps/libui/darwin/form.o \ - deps/libui/darwin/grid.o \ - deps/libui/darwin/group.o \ - deps/libui/darwin/image.o \ - deps/libui/darwin/label.o \ - deps/libui/darwin/main.o \ - deps/libui/darwin/map.o \ - deps/libui/darwin/menu.o \ - deps/libui/darwin/multilineentry.o \ - deps/libui/darwin/progressbar.o \ - deps/libui/darwin/radiobuttons.o \ - deps/libui/darwin/scrollview.o \ - deps/libui/darwin/separator.o \ - deps/libui/darwin/slider.o \ - deps/libui/darwin/spinbox.o \ - deps/libui/darwin/stddialogs.o \ - deps/libui/darwin/tab.o \ - deps/libui/darwin/text.o \ - deps/libui/darwin/util.o \ - deps/libui/darwin/window.o \ - deps/libui/darwin/winmoveresize.o -else -CFLAGS += -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/atk-1.0 -LIBS += -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -OBJ += deps/libui/unix/alloc.o \ - deps/libui/unix/area.o \ - deps/libui/unix/box.o \ - deps/libui/unix/button.o \ - deps/libui/unix/cellrendererbutton.o \ - deps/libui/unix/checkbox.o \ - deps/libui/unix/child.o \ - deps/libui/unix/colorbutton.o \ - deps/libui/unix/combobox.o \ - deps/libui/unix/control.o \ - deps/libui/unix/datetimepicker.o \ - deps/libui/unix/debug.o \ - deps/libui/unix/draw.o \ - deps/libui/unix/drawmatrix.o \ - deps/libui/unix/drawpath.o \ - deps/libui/unix/drawtext.o \ - deps/libui/unix/editablecombo.o \ - deps/libui/unix/entry.o \ - deps/libui/unix/fontbutton.o \ - deps/libui/unix/form.o \ - deps/libui/unix/future.o \ - deps/libui/unix/graphemes.o \ - deps/libui/unix/grid.o \ - deps/libui/unix/group.o \ - deps/libui/unix/image.o \ - deps/libui/unix/label.o \ - deps/libui/unix/main.o \ - deps/libui/unix/menu.o \ - deps/libui/unix/multilineentry.o \ - deps/libui/unix/progressbar.o \ - deps/libui/unix/radiobuttons.o \ - deps/libui/unix/separator.o \ - deps/libui/unix/slider.o \ - deps/libui/unix/spinbox.o \ - deps/libui/unix/stddialogs.o \ - deps/libui/unix/tab.o \ - deps/libui/unix/text.o \ - deps/libui/unix/util.o \ - deps/libui/unix/window.o -endif -endif - -OBJ += deps/libui/common/areaevents.o \ - deps/libui/common/control.o \ - deps/libui/common/debug.o \ - deps/libui/common/matrix.o \ - deps/libui/common/shouldquit.o \ - deps/libui/common/userbugs.o - -OBJ += deps/libui/libui_main.o -endif -endif - # Miscellaneous ifeq ($(HAVE_STDIN_CMD), 1) diff --git a/command.c b/command.c index 0c128985f4..837929f506 100644 --- a/command.c +++ b/command.c @@ -2886,12 +2886,6 @@ TODO: Add a setting for these tweaks */ case CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET: command_event_restore_default_shader_preset(); break; - case CMD_EVENT_LIBUI_TEST: -#if HAVE_LIBUI - extern int libui_main(void); - libui_main(); -#endif - break; case CMD_EVENT_DISCORD_INIT: #ifdef HAVE_DISCORD { diff --git a/command.h b/command.h index 1a7e84fac7..85712bd027 100644 --- a/command.h +++ b/command.h @@ -235,8 +235,7 @@ enum event_command CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, CMD_EVENT_DISCORD_INIT, CMD_EVENT_DISCORD_DEINIT, - CMD_EVENT_DISCORD_UPDATE, - CMD_EVENT_LIBUI_TEST + CMD_EVENT_DISCORD_UPDATE }; bool command_set_shader(const char *arg); diff --git a/deps/libui/LICENSE b/deps/libui/LICENSE deleted file mode 100644 index 2351d66d93..0000000000 --- a/deps/libui/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -Copyright (c) 2014 Pietro Gagliardi - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -(this is called the MIT License or Expat License; see http://www.opensource.org/licenses/MIT) diff --git a/deps/libui/common/CMakeLists.txt b/deps/libui/common/CMakeLists.txt deleted file mode 100644 index 91d794936f..0000000000 --- a/deps/libui/common/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# 3 june 2016 - -list(APPEND _LIBUI_SOURCES - common/areaevents.c - common/control.c - common/debug.c - common/matrix.c - common/shouldquit.c - common/userbugs.c -) -set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) - -list(APPEND _LIBUI_INCLUDEDIRS - common -) -set(_LIBUI_INCLUDEDIRS ${_LIBUI_INCLUDEDIRS} PARENT_SCOPE) diff --git a/deps/libui/common/areaevents.c b/deps/libui/common/areaevents.c deleted file mode 100644 index cf3c288c4f..0000000000 --- a/deps/libui/common/areaevents.c +++ /dev/null @@ -1,167 +0,0 @@ -// 29 march 2014 -#include "../ui.h" -#include "uipriv.h" - -/* -Windows and GTK+ have a limit of 2 and 3 clicks, respectively, natively supported. Fortunately, we can simulate the double/triple-click behavior to build higher-order clicks. We can use the same algorithm Windows uses on both: - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/18/243925.aspx -For GTK+, we pull the double-click time and double-click distance, which work the same as the equivalents on Windows (so the distance is in all directions), from the GtkSettings system. - -On GTK+ this will also allow us to discard the GDK_BUTTON_2PRESS and GDK_BUTTON_3PRESS events, so the button press stream will be just like on other platforms. - -Thanks to mclasen, garnacho_, halfline, and tristan in irc.gimp.net/#gtk+. -*/ - -// x, y, xdist, ydist, and c.rect must have the same units -// so must time, maxTime, and c.prevTime -int clickCounterClick(clickCounter *c, int button, int x, int y, uintptr_t time, uintptr_t maxTime, int32_t xdist, int32_t ydist) -{ - // different button than before? if so, don't count - if (button != c->curButton) - c->count = 0; - - // (x, y) in the allowed region for a double-click? if not, don't count - if (x < c->rectX0) - c->count = 0; - if (y < c->rectY0) - c->count = 0; - if (x >= c->rectX1) - c->count = 0; - if (y >= c->rectY1) - c->count = 0; - - // too slow? if so, don't count - // note the below expression; time > (c.prevTime + maxTime) can overflow! - if ((time - c->prevTime) > maxTime) // too slow; don't count - c->count = 0; - - c->count++; // if either of the above ifs happened, this will make the click count 1; otherwise it will make the click count 2, 3, 4, 5, ... - - // now we need to update the internal structures for the next test - c->curButton = button; - c->prevTime = time; - c->rectX0 = x - xdist; - c->rectY0 = y - ydist; - c->rectX1 = x + xdist; - c->rectY1 = y + ydist; - - return c->count; -} - -void clickCounterReset(clickCounter *c) -{ - c->curButton = 0; - c->rectX0 = 0; - c->rectY0 = 0; - c->rectX1 = 0; - c->rectY1 = 0; - c->prevTime = 0; - c->count = 0; -} - -/* -For position independence across international keyboard layouts, typewriter keys are read using scancodes (which are always set 1). -Windows provides the scancodes directly in the LPARAM. -GTK+ provides the scancodes directly from the underlying window system via GdkEventKey.hardware_keycode. -On X11, this is scancode + 8 (because X11 keyboard codes have a range of [8,255]). -Wayland is guaranteed to give the same result (thanks ebassi in irc.gimp.net/#gtk+). -On Linux, where evdev is used instead of polling scancodes directly from the keyboard, evdev's typewriter section key code constants are the same as scancodes anyway, so the rules above apply. -Typewriter section scancodes are the same across international keyboards with some exceptions that have been accounted for (see KeyEvent's documentation); see http://www.quadibloc.com/comp/scan.htm for details. -Non-typewriter keys can be handled safely using constants provided by the respective backend API. - -Because GTK+ keysyms may or may not obey Num Lock, we also handle the 0-9 and . keys on the numeric keypad with scancodes (they match too). -*/ - -// use uintptr_t to be safe; the size of the scancode/hardware key code field on each platform is different -static const struct { - uintptr_t scancode; - char equiv; -} scancodeKeys[] = { - { 0x02, '1' }, - { 0x03, '2' }, - { 0x04, '3' }, - { 0x05, '4' }, - { 0x06, '5' }, - { 0x07, '6' }, - { 0x08, '7' }, - { 0x09, '8' }, - { 0x0A, '9' }, - { 0x0B, '0' }, - { 0x0C, '-' }, - { 0x0D, '=' }, - { 0x0E, '\b' }, - { 0x0F, '\t' }, - { 0x10, 'q' }, - { 0x11, 'w' }, - { 0x12, 'e' }, - { 0x13, 'r' }, - { 0x14, 't' }, - { 0x15, 'y' }, - { 0x16, 'u' }, - { 0x17, 'i' }, - { 0x18, 'o' }, - { 0x19, 'p' }, - { 0x1A, '[' }, - { 0x1B, ']' }, - { 0x1C, '\n' }, - { 0x1E, 'a' }, - { 0x1F, 's' }, - { 0x20, 'd' }, - { 0x21, 'f' }, - { 0x22, 'g' }, - { 0x23, 'h' }, - { 0x24, 'j' }, - { 0x25, 'k' }, - { 0x26, 'l' }, - { 0x27, ';' }, - { 0x28, '\'' }, - { 0x29, '`' }, - { 0x2B, '\\' }, - { 0x2C, 'z' }, - { 0x2D, 'x' }, - { 0x2E, 'c' }, - { 0x2F, 'v' }, - { 0x30, 'b' }, - { 0x31, 'n' }, - { 0x32, 'm' }, - { 0x33, ',' }, - { 0x34, '.' }, - { 0x35, '/' }, - { 0x39, ' ' }, - { 0xFFFF, 0 }, -}; - -static const struct { - uintptr_t scancode; - uiExtKey equiv; -} scancodeExtKeys[] = { - { 0x47, uiExtKeyN7 }, - { 0x48, uiExtKeyN8 }, - { 0x49, uiExtKeyN9 }, - { 0x4B, uiExtKeyN4 }, - { 0x4C, uiExtKeyN5 }, - { 0x4D, uiExtKeyN6 }, - { 0x4F, uiExtKeyN1 }, - { 0x50, uiExtKeyN2 }, - { 0x51, uiExtKeyN3 }, - { 0x52, uiExtKeyN0 }, - { 0x53, uiExtKeyNDot }, - { 0xFFFF, 0 }, -}; - -int fromScancode(uintptr_t scancode, uiAreaKeyEvent *ke) -{ - int i; - - for (i = 0; scancodeKeys[i].scancode != 0xFFFF; i++) - if (scancodeKeys[i].scancode == scancode) { - ke->Key = scancodeKeys[i].equiv; - return 1; - } - for (i = 0; scancodeExtKeys[i].scancode != 0xFFFF; i++) - if (scancodeExtKeys[i].scancode == scancode) { - ke->ExtKey = scancodeExtKeys[i].equiv; - return 1; - } - return 0; -} diff --git a/deps/libui/common/control.c b/deps/libui/common/control.c deleted file mode 100644 index 2806646168..0000000000 --- a/deps/libui/common/control.c +++ /dev/null @@ -1,101 +0,0 @@ -// 26 may 2015 -#include "../ui.h" -#include "uipriv.h" - -void uiControlDestroy(uiControl *c) -{ - (*(c->Destroy))(c); -} - -uintptr_t uiControlHandle(uiControl *c) -{ - return (*(c->Handle))(c); -} - -uiControl *uiControlParent(uiControl *c) -{ - return (*(c->Parent))(c); -} - -void uiControlSetParent(uiControl *c, uiControl *parent) -{ - (*(c->SetParent))(c, parent); -} - -int uiControlToplevel(uiControl *c) -{ - return (*(c->Toplevel))(c); -} - -int uiControlVisible(uiControl *c) -{ - return (*(c->Visible))(c); -} - -void uiControlShow(uiControl *c) -{ - (*(c->Show))(c); -} - -void uiControlHide(uiControl *c) -{ - (*(c->Hide))(c); -} - -int uiControlEnabled(uiControl *c) -{ - return (*(c->Enabled))(c); -} - -void uiControlEnable(uiControl *c) -{ - (*(c->Enable))(c); -} - -void uiControlDisable(uiControl *c) -{ - (*(c->Disable))(c); -} - -#define uiControlSignature 0x7569436F - -uiControl *uiAllocControl(size_t size, uint32_t OSsig, uint32_t typesig, const char *typenamestr) -{ - uiControl *c; - - c = (uiControl *) uiAlloc(size, typenamestr); - c->Signature = uiControlSignature; - c->OSSignature = OSsig; - c->TypeSignature = typesig; - return c; -} - -void uiFreeControl(uiControl *c) -{ - if (uiControlParent(c) != NULL) - userbug("You cannot destroy a uiControl while it still has a parent. (control: %p)", c); - uiFree(c); -} - -void uiControlVerifySetParent(uiControl *c, uiControl *parent) -{ - uiControl *curParent; - - if (uiControlToplevel(c)) - userbug("You cannot give a toplevel uiControl a parent. (control: %p)", c); - curParent = uiControlParent(c); - if (parent != NULL && curParent != NULL) - userbug("You cannot give a uiControl a parent while it already has one. (control: %p; current parent: %p; new parent: %p)", c, curParent, parent); - if (parent == NULL && curParent == NULL) - implbug("attempt to double unparent uiControl %p", c); -} - -int uiControlEnabledToUser(uiControl *c) -{ - while (c != NULL) { - if (!uiControlEnabled(c)) - return 0; - c = uiControlParent(c); - } - return 1; -} diff --git a/deps/libui/common/controlsigs.h b/deps/libui/common/controlsigs.h deleted file mode 100644 index 1cbf18d5da..0000000000 --- a/deps/libui/common/controlsigs.h +++ /dev/null @@ -1,25 +0,0 @@ -// 24 april 2016 - -#define uiAreaSignature 0x41726561 -#define uiBoxSignature 0x426F784C -#define uiButtonSignature 0x42746F6E -#define uiCheckboxSignature 0x43686B62 -#define uiColorButtonSignature 0x436F6C42 -#define uiComboboxSignature 0x436F6D62 -#define uiDateTimePickerSignature 0x44545069 -#define uiEditableComboboxSignature 0x45644362 -#define uiEntrySignature 0x456E7472 -#define uiFontButtonSignature 0x466F6E42 -#define uiFormSignature 0x466F726D -#define uiGridSignature 0x47726964 -#define uiGroupSignature 0x47727062 -#define uiLabelSignature 0x4C61626C -#define uiMultilineEntrySignature 0x4D6C6E45 -#define uiProgressBarSignature 0x50426172 -#define uiRadioButtonsSignature 0x5264696F -#define uiSeparatorSignature 0x53657061 -#define uiSliderSignature 0x536C6964 -#define uiSpinboxSignature 0x5370696E -#define uiTabSignature 0x54616273 -#define uiTableSignature 0x5461626C -#define uiWindowSignature 0x57696E64 diff --git a/deps/libui/common/debug.c b/deps/libui/common/debug.c deleted file mode 100644 index 97280b47ba..0000000000 --- a/deps/libui/common/debug.c +++ /dev/null @@ -1,21 +0,0 @@ -// 13 may 2016 -#include "../ui.h" -#include "uipriv.h" - -void _implbug(const char *file, const char *line, const char *func, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - realbug(file, line, func, "POSSIBLE IMPLEMENTATION BUG; CONTACT ANDLABS:\n", format, ap); - va_end(ap); -} - -void _userbug(const char *file, const char *line, const char *func, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - realbug(file, line, func, "You have a bug: ", format, ap); - va_end(ap); -} diff --git a/deps/libui/common/matrix.c b/deps/libui/common/matrix.c deleted file mode 100644 index 676885d1bf..0000000000 --- a/deps/libui/common/matrix.c +++ /dev/null @@ -1,50 +0,0 @@ -// 11 october 2015 -#include -#include "../ui.h" -#include "uipriv.h" - -void uiDrawMatrixSetIdentity(uiDrawMatrix *m) -{ - m->M11 = 1; - m->M12 = 0; - m->M21 = 0; - m->M22 = 1; - m->M31 = 0; - m->M32 = 0; -} - -// The rest of this file provides basic utilities in case the platform doesn't provide any of its own for these tasks. -// Keep these as minimal as possible. They should generally not call other fallbacks. - -// see https://msdn.microsoft.com/en-us/library/windows/desktop/ff684171%28v=vs.85%29.aspx#skew_transform -// TODO see if there's a way we can avoid the multiplication -void fallbackSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount) -{ - uiDrawMatrix n; - - uiDrawMatrixSetIdentity(&n); - // TODO explain this - n.M12 = tan(yamount); - n.M21 = tan(xamount); - n.M31 = -y * tan(xamount); - n.M32 = -x * tan(yamount); - uiDrawMatrixMultiply(m, &n); -} - -void scaleCenter(double xCenter, double yCenter, double *x, double *y) -{ - *x = xCenter - (*x * xCenter); - *y = yCenter - (*y * yCenter); -} - -// the basic algorithm is from cairo -// but it's the same algorithm as the transform point, just without M31 and M32 taken into account, so let's just do that instead -void fallbackTransformSize(uiDrawMatrix *m, double *x, double *y) -{ - uiDrawMatrix m2; - - m2 = *m; - m2.M31 = 0; - m2.M32 = 0; - uiDrawMatrixTransformPoint(&m2, x, y); -} diff --git a/deps/libui/common/shouldquit.c b/deps/libui/common/shouldquit.c deleted file mode 100644 index 4e7aa5c322..0000000000 --- a/deps/libui/common/shouldquit.c +++ /dev/null @@ -1,22 +0,0 @@ -// 9 may 2015 -#include "../ui.h" -#include "uipriv.h" - -static int defaultOnShouldQuit(void *data) -{ - return 0; -} - -static int (*onShouldQuit)(void *) = defaultOnShouldQuit; -static void *onShouldQuitData; - -void uiOnShouldQuit(int (*f)(void *), void *data) -{ - onShouldQuit = f; - onShouldQuitData = data; -} - -int shouldQuit(void) -{ - return (*onShouldQuit)(onShouldQuitData); -} diff --git a/deps/libui/common/uipriv.h b/deps/libui/common/uipriv.h deleted file mode 100644 index d6b54e89ad..0000000000 --- a/deps/libui/common/uipriv.h +++ /dev/null @@ -1,58 +0,0 @@ -// 6 april 2015 -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "controlsigs.h" - -extern uiInitOptions options; - -extern void *uiAlloc(size_t, const char *); -#define uiNew(T) ((T *) uiAlloc(sizeof (T), #T)) -extern void *uiRealloc(void *, size_t, const char *); -extern void uiFree(void *); - -// ugh, this was only introduced in MSVC 2015... -#ifdef _MSC_VER -#define __func__ __FUNCTION__ -#endif -extern void realbug(const char *file, const char *line, const char *func, const char *prefix, const char *format, va_list ap); -#define _ns2(s) #s -#define _ns(s) _ns2(s) -extern void _implbug(const char *file, const char *line, const char *func, const char *format, ...); -#define implbug(...) _implbug(__FILE__, _ns(__LINE__), __func__, __VA_ARGS__) -extern void _userbug(const char *file, const char *line, const char *func, const char *format, ...); -#define userbug(...) _userbug(__FILE__, _ns(__LINE__), __func__, __VA_ARGS__) - -// control.c -extern uiControl *newControl(size_t size, uint32_t OSsig, uint32_t typesig, const char *typenamestr); - -// shouldquit.c -extern int shouldQuit(void); - -// areaevents.c -typedef struct clickCounter clickCounter; -// you should call Reset() to zero-initialize a new instance -// it doesn't matter that all the non-count fields are zero: the first click will fail the curButton test straightaway, so it'll return 1 and set the rest of the structure accordingly -struct clickCounter { - int curButton; - int rectX0; - int rectY0; - int rectX1; - int rectY1; - uintptr_t prevTime; - int count; -}; -int clickCounterClick(clickCounter *c, int button, int x, int y, uintptr_t time, uintptr_t maxTime, int32_t xdist, int32_t ydist); -extern void clickCounterReset(clickCounter *); -extern int fromScancode(uintptr_t, uiAreaKeyEvent *); - -// matrix.c -extern void fallbackSkew(uiDrawMatrix *, double, double, double, double); -extern void scaleCenter(double, double, double *, double *); -extern void fallbackTransformSize(uiDrawMatrix *, double *, double *); - -#ifdef __cplusplus -} -#endif diff --git a/deps/libui/common/userbugs.c b/deps/libui/common/userbugs.c deleted file mode 100644 index 0a85874c91..0000000000 --- a/deps/libui/common/userbugs.c +++ /dev/null @@ -1,8 +0,0 @@ -// 22 may 2016 -#include "../ui.h" -#include "uipriv.h" - -void uiUserBugCannotSetParentOnToplevel(const char *type) -{ - userbug("You cannot make a %s a child of another uiControl,", type); -} diff --git a/deps/libui/darwin/CMakeLists.txt b/deps/libui/darwin/CMakeLists.txt deleted file mode 100644 index dbef5d432c..0000000000 --- a/deps/libui/darwin/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -# 3 june 2016 - -list(APPEND _LIBUI_SOURCES - darwin/alloc.m - darwin/area.m - darwin/areaevents.m - darwin/autolayout.m - darwin/box.m - darwin/button.m - darwin/checkbox.m - darwin/colorbutton.m - darwin/combobox.m - darwin/control.m - darwin/datetimepicker.m - darwin/debug.m - darwin/draw.m - darwin/drawtext.m - darwin/editablecombo.m - darwin/entry.m - darwin/fontbutton.m - darwin/form.m - darwin/grid.m - darwin/group.m - darwin/image.m - darwin/label.m - darwin/main.m - darwin/map.m - darwin/menu.m - darwin/multilineentry.m - darwin/progressbar.m - darwin/radiobuttons.m - darwin/scrollview.m - darwin/separator.m - darwin/slider.m - darwin/spinbox.m - darwin/stddialogs.m - darwin/tab.m - darwin/text.m - darwin/util.m - darwin/window.m - darwin/winmoveresize.m -) -set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) - -list(APPEND _LIBUI_INCLUDEDIRS - darwin -) -set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE) - -set(_LIBUINAME libui PARENT_SCOPE) -if(NOT BUILD_SHARED_LIBS) - set(_LIBUINAME libui-temporary PARENT_SCOPE) -endif() -# thanks to Mr-Hide in irc.freenode.net/#cmake -macro(_handle_static) - set_target_properties(${_LIBUINAME} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") - set(_aname $) - set(_lname libui-combined.list) - set(_oname libui-combined.o) - add_custom_command( - OUTPUT ${_oname} - COMMAND - nm -m ${_aname} | sed -E -n "'s/^[0-9a-f]* \\([A-Z_]+,[a-z_]+\\) external //p'" > ${_lname} - COMMAND - ld -exported_symbols_list ${_lname} -r -all_load ${_aname} -o ${_oname} - COMMENT "Removing hidden symbols") - add_library(libui STATIC ${_oname}) - # otherwise cmake won't know which linker to use - set_target_properties(libui PROPERTIES - LINKER_LANGUAGE C) - set(_aname) - set(_lname) - set(_oname) -endmacro() - -set(_LIBUI_LIBS - objc "-framework Foundation" "-framework AppKit" -PARENT_SCOPE) diff --git a/deps/libui/darwin/alloc.m b/deps/libui/darwin/alloc.m deleted file mode 100644 index e271b90ec1..0000000000 --- a/deps/libui/darwin/alloc.m +++ /dev/null @@ -1,89 +0,0 @@ -// 4 december 2014 -#import -#import "uipriv_darwin.h" - -static NSMutableArray *allocations; -NSMutableArray *delegates; - -void initAlloc(void) -{ - allocations = [NSMutableArray new]; - delegates = [NSMutableArray new]; -} - -#define UINT8(p) ((uint8_t *) (p)) -#define PVOID(p) ((void *) (p)) -#define EXTRA (sizeof (size_t) + sizeof (const char **)) -#define DATA(p) PVOID(UINT8(p) + EXTRA) -#define BASE(p) PVOID(UINT8(p) - EXTRA) -#define SIZE(p) ((size_t *) (p)) -#define CCHAR(p) ((const char **) (p)) -#define TYPE(p) CCHAR(UINT8(p) + sizeof (size_t)) - -void uninitAlloc(void) -{ - NSMutableString *str; - NSValue *v; - - [delegates release]; - if ([allocations count] == 0) { - [allocations release]; - return; - } - str = [NSMutableString new]; - for (v in allocations) { - void *ptr; - - ptr = [v pointerValue]; - [str appendString:[NSString stringWithFormat:@"%p %s\n", ptr, *TYPE(ptr)]]; - } - userbug("Some data was leaked; either you left a uiControl lying around or there's a bug in libui itself. Leaked data:\n%s", [str UTF8String]); - [str release]; -} - -void *uiAlloc(size_t size, const char *type) -{ - void *out; - - out = malloc(EXTRA + size); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiAlloc()\n"); - abort(); - } - memset(DATA(out), 0, size); - *SIZE(out) = size; - *TYPE(out) = type; - [allocations addObject:[NSValue valueWithPointer:out]]; - return DATA(out); -} - -void *uiRealloc(void *p, size_t new, const char *type) -{ - void *out; - size_t *s; - - if (p == NULL) - return uiAlloc(new, type); - p = BASE(p); - out = realloc(p, EXTRA + new); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiRealloc()\n"); - abort(); - } - s = SIZE(out); - if (new <= *s) - memset(((uint8_t *) DATA(out)) + *s, 0, new - *s); - *s = new; - [allocations removeObject:[NSValue valueWithPointer:p]]; - [allocations addObject:[NSValue valueWithPointer:out]]; - return DATA(out); -} - -void uiFree(void *p) -{ - if (p == NULL) - implbug("attempt to uiFree(NULL)"); - p = BASE(p); - free(p); - [allocations removeObject:[NSValue valueWithPointer:p]]; -} diff --git a/deps/libui/darwin/area.m b/deps/libui/darwin/area.m deleted file mode 100644 index 23162e6cff..0000000000 --- a/deps/libui/darwin/area.m +++ /dev/null @@ -1,475 +0,0 @@ -// 9 september 2015 -#import "uipriv_darwin.h" - -// 10.8 fixups -#define NSEventModifierFlags NSUInteger - -@interface areaView : NSView { - uiArea *libui_a; - NSTrackingArea *libui_ta; - NSSize libui_ss; - BOOL libui_enabled; -} -- (id)initWithFrame:(NSRect)r area:(uiArea *)a; -- (uiModifiers)parseModifiers:(NSEvent *)e; -- (void)doMouseEvent:(NSEvent *)e; -- (int)sendKeyEvent:(uiAreaKeyEvent *)ke; -- (int)doKeyDownUp:(NSEvent *)e up:(int)up; -- (int)doKeyDown:(NSEvent *)e; -- (int)doKeyUp:(NSEvent *)e; -- (int)doFlagsChanged:(NSEvent *)e; -- (void)setupNewTrackingArea; -- (void)setScrollingSize:(NSSize)s; -- (BOOL)isEnabled; -- (void)setEnabled:(BOOL)e; -@end - -struct uiArea { - uiDarwinControl c; - NSView *view; // either sv or area depending on whether it is scrolling - NSScrollView *sv; - areaView *area; - struct scrollViewData *d; - uiAreaHandler *ah; - BOOL scrolling; - NSEvent *dragevent; -}; - -@implementation areaView - -- (id)initWithFrame:(NSRect)r area:(uiArea *)a -{ - self = [super initWithFrame:r]; - if (self) { - self->libui_a = a; - [self setupNewTrackingArea]; - self->libui_ss = r.size; - self->libui_enabled = YES; - } - return self; -} - -- (void)drawRect:(NSRect)r -{ - uiArea *a = self->libui_a; - CGContextRef c; - uiAreaDrawParams dp; - - c = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; - // see draw.m under text for why we need the height - dp.Context = newContext(c, [self bounds].size.height); - - dp.AreaWidth = 0; - dp.AreaHeight = 0; - if (!a->scrolling) { - dp.AreaWidth = [self frame].size.width; - dp.AreaHeight = [self frame].size.height; - } - - dp.ClipX = r.origin.x; - dp.ClipY = r.origin.y; - dp.ClipWidth = r.size.width; - dp.ClipHeight = r.size.height; - - // no need to save or restore the graphics state to reset transformations; Cocoa creates a brand-new context each time - (*(a->ah->Draw))(a->ah, a, &dp); - - freeContext(dp.Context); -} - -- (BOOL)isFlipped -{ - return YES; -} - -- (BOOL)acceptsFirstResponder -{ - return YES; -} - -- (uiModifiers)parseModifiers:(NSEvent *)e -{ - NSEventModifierFlags mods; - uiModifiers m; - - m = 0; - mods = [e modifierFlags]; - if ((mods & NSControlKeyMask) != 0) - m |= uiModifierCtrl; - if ((mods & NSAlternateKeyMask) != 0) - m |= uiModifierAlt; - if ((mods & NSShiftKeyMask) != 0) - m |= uiModifierShift; - if ((mods & NSCommandKeyMask) != 0) - m |= uiModifierSuper; - return m; -} - -- (void)setupNewTrackingArea -{ - self->libui_ta = [[NSTrackingArea alloc] initWithRect:[self bounds] - options:(NSTrackingMouseEnteredAndExited | - NSTrackingMouseMoved | - NSTrackingActiveAlways | - NSTrackingInVisibleRect | - NSTrackingEnabledDuringMouseDrag) - owner:self - userInfo:nil]; - [self addTrackingArea:self->libui_ta]; -} - -- (void)updateTrackingAreas -{ - [self removeTrackingArea:self->libui_ta]; - [self->libui_ta release]; - [self setupNewTrackingArea]; -} - -// capture on drag is done automatically on OS X -- (void)doMouseEvent:(NSEvent *)e -{ - uiArea *a = self->libui_a; - uiAreaMouseEvent me; - NSPoint point; - int buttonNumber; - NSUInteger pmb; - unsigned int i, max; - - // this will convert point to drawing space - // thanks swillits in irc.freenode.net/#macdev - point = [self convertPoint:[e locationInWindow] fromView:nil]; - me.X = point.x; - me.Y = point.y; - - me.AreaWidth = 0; - me.AreaHeight = 0; - if (!a->scrolling) { - me.AreaWidth = [self frame].size.width; - me.AreaHeight = [self frame].size.height; - } - - buttonNumber = [e buttonNumber] + 1; - // swap button numbers 2 and 3 (right and middle) - if (buttonNumber == 2) - buttonNumber = 3; - else if (buttonNumber == 3) - buttonNumber = 2; - - me.Down = 0; - me.Up = 0; - me.Count = 0; - switch ([e type]) { - case NSLeftMouseDown: - case NSRightMouseDown: - case NSOtherMouseDown: - me.Down = buttonNumber; - me.Count = [e clickCount]; - break; - case NSLeftMouseUp: - case NSRightMouseUp: - case NSOtherMouseUp: - me.Up = buttonNumber; - break; - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: - // we include the button that triggered the dragged event in the Held fields - buttonNumber = 0; - break; - } - - me.Modifiers = [self parseModifiers:e]; - - pmb = [NSEvent pressedMouseButtons]; - me.Held1To64 = 0; - if (buttonNumber != 1 && (pmb & 1) != 0) - me.Held1To64 |= 1; - if (buttonNumber != 2 && (pmb & 4) != 0) - me.Held1To64 |= 2; - if (buttonNumber != 3 && (pmb & 2) != 0) - me.Held1To64 |= 4; - // buttons 4..32 - // https://developer.apple.com/library/mac/documentation/Carbon/Reference/QuartzEventServicesRef/index.html#//apple_ref/c/tdef/CGMouseButton says Quartz only supports up to 32 buttons - max = 32; - for (i = 4; i <= max; i++) { - uint64_t j; - - if (buttonNumber == i) - continue; - j = 1 << (i - 1); - if ((pmb & j) != 0) - me.Held1To64 |= j; - } - - if (self->libui_enabled) { - // and allow dragging here - a->dragevent = e; - (*(a->ah->MouseEvent))(a->ah, a, &me); - a->dragevent = nil; - } -} - -#define mouseEvent(name) \ - - (void)name:(NSEvent *)e \ - { \ - [self doMouseEvent:e]; \ - } -mouseEvent(mouseMoved) -mouseEvent(mouseDragged) -mouseEvent(rightMouseDragged) -mouseEvent(otherMouseDragged) -mouseEvent(mouseDown) -mouseEvent(rightMouseDown) -mouseEvent(otherMouseDown) -mouseEvent(mouseUp) -mouseEvent(rightMouseUp) -mouseEvent(otherMouseUp) - -- (void)mouseEntered:(NSEvent *)e -{ - uiArea *a = self->libui_a; - - if (self->libui_enabled) - (*(a->ah->MouseCrossed))(a->ah, a, 0); -} - -- (void)mouseExited:(NSEvent *)e -{ - uiArea *a = self->libui_a; - - if (self->libui_enabled) - (*(a->ah->MouseCrossed))(a->ah, a, 1); -} - -// note: there is no equivalent to WM_CAPTURECHANGED on Mac OS X; there literally is no way to break a grab like that -// even if I invoke the task switcher and switch processes, the mouse grab will still be held until I let go of all buttons -// therefore, no DragBroken() - -- (int)sendKeyEvent:(uiAreaKeyEvent *)ke -{ - uiArea *a = self->libui_a; - - return (*(a->ah->KeyEvent))(a->ah, a, ke); -} - -- (int)doKeyDownUp:(NSEvent *)e up:(int)up -{ - uiAreaKeyEvent ke; - - ke.Key = 0; - ke.ExtKey = 0; - ke.Modifier = 0; - - ke.Modifiers = [self parseModifiers:e]; - - ke.Up = up; - - if (!fromKeycode([e keyCode], &ke)) - return 0; - return [self sendKeyEvent:&ke]; -} - -- (int)doKeyDown:(NSEvent *)e -{ - return [self doKeyDownUp:e up:0]; -} - -- (int)doKeyUp:(NSEvent *)e -{ - return [self doKeyDownUp:e up:1]; -} - -- (int)doFlagsChanged:(NSEvent *)e -{ - uiAreaKeyEvent ke; - uiModifiers whichmod; - - ke.Key = 0; - ke.ExtKey = 0; - - // Mac OS X sends this event on both key up and key down. - // Fortunately -[e keyCode] IS valid here, so we can simply map from key code to Modifiers, get the value of [e modifierFlags], and check if the respective bit is set or not — that will give us the up/down state - if (!keycodeModifier([e keyCode], &whichmod)) - return 0; - ke.Modifier = whichmod; - ke.Modifiers = [self parseModifiers:e]; - ke.Up = (ke.Modifiers & ke.Modifier) == 0; - // and then drop the current modifier from Modifiers - ke.Modifiers &= ~ke.Modifier; - return [self sendKeyEvent:&ke]; -} - -- (void)setFrameSize:(NSSize)size -{ - uiArea *a = self->libui_a; - - [super setFrameSize:size]; - if (!a->scrolling) - // we must redraw everything on resize because Windows requires it - [self setNeedsDisplay:YES]; -} - -// TODO does this update the frame? -- (void)setScrollingSize:(NSSize)s -{ - self->libui_ss = s; - [self invalidateIntrinsicContentSize]; -} - -- (NSSize)intrinsicContentSize -{ - if (!self->libui_a->scrolling) - return [super intrinsicContentSize]; - return self->libui_ss; -} - -- (BOOL)becomeFirstResponder -{ - return [self isEnabled]; -} - -- (BOOL)isEnabled -{ - return self->libui_enabled; -} - -- (void)setEnabled:(BOOL)e -{ - self->libui_enabled = e; - if (!self->libui_enabled && [self window] != nil) - if ([[self window] firstResponder] == self) - [[self window] makeFirstResponder:nil]; -} - -@end - -uiDarwinControlAllDefaultsExceptDestroy(uiArea, view) - -static void uiAreaDestroy(uiControl *c) -{ - uiArea *a = uiArea(c); - - if (a->scrolling) - scrollViewFreeData(a->sv, a->d); - [a->area release]; - if (a->scrolling) - [a->sv release]; - uiFreeControl(uiControl(a)); -} - -// called by subclasses of -[NSApplication sendEvent:] -// by default, NSApplication eats some key events -// this prevents that from happening with uiArea -// see http://stackoverflow.com/questions/24099063/how-do-i-detect-keyup-in-my-nsview-with-the-command-key-held and http://lists.apple.com/archives/cocoa-dev/2003/Oct/msg00442.html -int sendAreaEvents(NSEvent *e) -{ - NSEventType type; - id focused; - areaView *view; - - type = [e type]; - if (type != NSKeyDown && type != NSKeyUp && type != NSFlagsChanged) - return 0; - focused = [[e window] firstResponder]; - if (focused == nil) - return 0; - if (![focused isKindOfClass:[areaView class]]) - return 0; - view = (areaView *) focused; - switch (type) { - case NSKeyDown: - return [view doKeyDown:e]; - case NSKeyUp: - return [view doKeyUp:e]; - case NSFlagsChanged: - return [view doFlagsChanged:e]; - } - return 0; -} - -void uiAreaSetSize(uiArea *a, int width, int height) -{ - if (!a->scrolling) - userbug("You cannot call uiAreaSetSize() on a non-scrolling uiArea. (area: %p)", a); - [a->area setScrollingSize:NSMakeSize(width, height)]; -} - -void uiAreaQueueRedrawAll(uiArea *a) -{ - [a->area setNeedsDisplay:YES]; -} - -void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height) -{ - if (!a->scrolling) - userbug("You cannot call uiAreaScrollTo() on a non-scrolling uiArea. (area: %p)", a); - [a->area scrollRectToVisible:NSMakeRect(x, y, width, height)]; - // don't worry about the return value; it just says whether scrolling was needed -} - -void uiAreaBeginUserWindowMove(uiArea *a) -{ - libuiNSWindow *w; - - w = (libuiNSWindow *) [a->area window]; - if (w == nil) - return; // TODO - if (a->dragevent == nil) - return; // TODO - [w libui_doMove:a->dragevent]; -} - -void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge) -{ - libuiNSWindow *w; - - w = (libuiNSWindow *) [a->area window]; - if (w == nil) - return; // TODO - if (a->dragevent == nil) - return; // TODO - [w libui_doResize:a->dragevent on:edge]; -} - -uiArea *uiNewArea(uiAreaHandler *ah) -{ - uiArea *a; - - uiDarwinNewControl(uiArea, a); - - a->ah = ah; - a->scrolling = NO; - - a->area = [[areaView alloc] initWithFrame:NSZeroRect area:a]; - - a->view = a->area; - - return a; -} - -uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height) -{ - uiArea *a; - struct scrollViewCreateParams p; - - uiDarwinNewControl(uiArea, a); - - a->ah = ah; - a->scrolling = YES; - - a->area = [[areaView alloc] initWithFrame:NSMakeRect(0, 0, width, height) - area:a]; - - memset(&p, 0, sizeof (struct scrollViewCreateParams)); - p.DocumentView = a->area; - p.BackgroundColor = [NSColor controlColor]; - p.DrawsBackground = 1; - p.Bordered = NO; - p.HScroll = YES; - p.VScroll = YES; - a->sv = mkScrollView(&p, &(a->d)); - - a->view = a->sv; - - return a; -} diff --git a/deps/libui/darwin/areaevents.m b/deps/libui/darwin/areaevents.m deleted file mode 100644 index d7ceaaadc5..0000000000 --- a/deps/libui/darwin/areaevents.m +++ /dev/null @@ -1,159 +0,0 @@ -// 30 march 2014 -#import "uipriv_darwin.h" - -/* -Mac OS X uses its own set of hardware key codes that are different from PC keyboard scancodes, but are positional (like PC keyboard scancodes). These are defined in , a Carbon header. As far as I can tell, there's no way to include this header without either using an absolute path or linking Carbon into the program, so the constant values are used here instead. - -The Cocoa docs do guarantee that -[NSEvent keyCode] results in key codes that are the same as those returned by Carbon; that is, these codes. -*/ - -// use uintptr_t to be safe -static const struct { - uintptr_t keycode; - char equiv; -} keycodeKeys[] = { - { 0x00, 'a' }, - { 0x01, 's' }, - { 0x02, 'd' }, - { 0x03, 'f' }, - { 0x04, 'h' }, - { 0x05, 'g' }, - { 0x06, 'z' }, - { 0x07, 'x' }, - { 0x08, 'c' }, - { 0x09, 'v' }, - { 0x0B, 'b' }, - { 0x0C, 'q' }, - { 0x0D, 'w' }, - { 0x0E, 'e' }, - { 0x0F, 'r' }, - { 0x10, 'y' }, - { 0x11, 't' }, - { 0x12, '1' }, - { 0x13, '2' }, - { 0x14, '3' }, - { 0x15, '4' }, - { 0x16, '6' }, - { 0x17, '5' }, - { 0x18, '=' }, - { 0x19, '9' }, - { 0x1A, '7' }, - { 0x1B, '-' }, - { 0x1C, '8' }, - { 0x1D, '0' }, - { 0x1E, ']' }, - { 0x1F, 'o' }, - { 0x20, 'u' }, - { 0x21, '[' }, - { 0x22, 'i' }, - { 0x23, 'p' }, - { 0x25, 'l' }, - { 0x26, 'j' }, - { 0x27, '\'' }, - { 0x28, 'k' }, - { 0x29, ';' }, - { 0x2A, '\\' }, - { 0x2B, ',' }, - { 0x2C, '/' }, - { 0x2D, 'n' }, - { 0x2E, 'm' }, - { 0x2F, '.' }, - { 0x32, '`' }, - { 0x24, '\n' }, - { 0x30, '\t' }, - { 0x31, ' ' }, - { 0x33, '\b' }, - { 0xFFFF, 0 }, -}; - -static const struct { - uintptr_t keycode; - uiExtKey equiv; -} keycodeExtKeys[] = { - { 0x41, uiExtKeyNDot }, - { 0x43, uiExtKeyNMultiply }, - { 0x45, uiExtKeyNAdd }, - { 0x4B, uiExtKeyNDivide }, - { 0x4C, uiExtKeyNEnter }, - { 0x4E, uiExtKeyNSubtract }, - { 0x52, uiExtKeyN0 }, - { 0x53, uiExtKeyN1 }, - { 0x54, uiExtKeyN2 }, - { 0x55, uiExtKeyN3 }, - { 0x56, uiExtKeyN4 }, - { 0x57, uiExtKeyN5 }, - { 0x58, uiExtKeyN6 }, - { 0x59, uiExtKeyN7 }, - { 0x5B, uiExtKeyN8 }, - { 0x5C, uiExtKeyN9 }, - { 0x35, uiExtKeyEscape }, - { 0x60, uiExtKeyF5 }, - { 0x61, uiExtKeyF6 }, - { 0x62, uiExtKeyF7 }, - { 0x63, uiExtKeyF3 }, - { 0x64, uiExtKeyF8 }, - { 0x65, uiExtKeyF9 }, - { 0x67, uiExtKeyF11 }, - { 0x6D, uiExtKeyF10 }, - { 0x6F, uiExtKeyF12 }, - { 0x72, uiExtKeyInsert }, // listed as the Help key but it's in the same position on an Apple keyboard as the Insert key on a Windows keyboard; thanks to SeanieB from irc.badnik.net and Psy in irc.freenode.net/#macdev for confirming they have the same code - { 0x73, uiExtKeyHome }, - { 0x74, uiExtKeyPageUp }, - { 0x75, uiExtKeyDelete }, - { 0x76, uiExtKeyF4 }, - { 0x77, uiExtKeyEnd }, - { 0x78, uiExtKeyF2 }, - { 0x79, uiExtKeyPageDown }, - { 0x7A, uiExtKeyF1 }, - { 0x7B, uiExtKeyLeft }, - { 0x7C, uiExtKeyRight }, - { 0x7D, uiExtKeyDown }, - { 0x7E, uiExtKeyUp }, - { 0xFFFF, 0 }, -}; - -static const struct { - uintptr_t keycode; - uiModifiers equiv; -} keycodeModifiers[] = { - { 0x37, uiModifierSuper }, // left command - { 0x38, uiModifierShift }, // left shift - { 0x3A, uiModifierAlt }, // left option - { 0x3B, uiModifierCtrl }, // left control - { 0x3C, uiModifierShift }, // right shift - { 0x3D, uiModifierAlt }, // right alt - { 0x3E, uiModifierCtrl }, // right control - // the following is not in Events.h for some reason - // thanks to Nicole and jedivulcan from irc.badnik.net - { 0x36, uiModifierSuper }, // right command - { 0xFFFF, 0 }, -}; - -BOOL fromKeycode(unsigned short keycode, uiAreaKeyEvent *ke) -{ - int i; - - for (i = 0; keycodeKeys[i].keycode != 0xFFFF; i++) - if (keycodeKeys[i].keycode == keycode) { - ke->Key = keycodeKeys[i].equiv; - return YES; - } - for (i = 0; keycodeExtKeys[i].keycode != 0xFFFF; i++) - if (keycodeExtKeys[i].keycode == keycode) { - ke->ExtKey = keycodeExtKeys[i].equiv; - return YES; - } - return NO; -} - -BOOL keycodeModifier(unsigned short keycode, uiModifiers *mod) -{ - int i; - - for (i = 0; keycodeModifiers[i].keycode != 0xFFFF; i++) - if (keycodeModifiers[i].keycode == keycode) { - *mod = keycodeModifiers[i].equiv; - return YES; - } - return NO; -} diff --git a/deps/libui/darwin/autolayout.m b/deps/libui/darwin/autolayout.m deleted file mode 100644 index 9964155fd3..0000000000 --- a/deps/libui/darwin/autolayout.m +++ /dev/null @@ -1,161 +0,0 @@ -// 15 august 2015 -#import "uipriv_darwin.h" - -NSLayoutConstraint *mkConstraint(id view1, NSLayoutAttribute attr1, NSLayoutRelation relation, id view2, NSLayoutAttribute attr2, CGFloat multiplier, CGFloat c, NSString *desc) -{ - NSLayoutConstraint *constraint; - - constraint = [NSLayoutConstraint constraintWithItem:view1 - attribute:attr1 - relatedBy:relation - toItem:view2 - attribute:attr2 - multiplier:multiplier - constant:c]; - // apparently only added in 10.9 - if ([constraint respondsToSelector:@selector(setIdentifier:)]) - [((id) constraint) setIdentifier:desc]; - return constraint; -} - -CGFloat uiDarwinMarginAmount(void *reserved) -{ - return 20.0; -} - -CGFloat uiDarwinPaddingAmount(void *reserved) -{ - return 8.0; -} - -// this is needed for NSSplitView to work properly; see http://stackoverflow.com/questions/34574478/how-can-i-set-the-position-of-a-nssplitview-nowadays-setpositionofdivideratind (stal in irc.freenode.net/#macdev came up with the exact combination) -// turns out it also works on NSTabView and NSBox too, possibly others! -// and for bonus points, it even seems to fix unsatisfiable-constraint-autoresizing-mask issues with NSTabView and NSBox too!!! this is nuts -void jiggleViewLayout(NSView *view) -{ - [view setNeedsLayout:YES]; - [view layoutSubtreeIfNeeded]; -} - -static CGFloat margins(int margined) -{ - if (!margined) - return 0.0; - return uiDarwinMarginAmount(NULL); -} - -void singleChildConstraintsEstablish(struct singleChildConstraints *c, NSView *contentView, NSView *childView, BOOL hugsTrailing, BOOL hugsBottom, int margined, NSString *desc) -{ - CGFloat margin; - - margin = margins(margined); - - c->leadingConstraint = mkConstraint(contentView, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - childView, NSLayoutAttributeLeading, - 1, -margin, - [desc stringByAppendingString:@" leading constraint"]); - [contentView addConstraint:c->leadingConstraint]; - [c->leadingConstraint retain]; - - c->topConstraint = mkConstraint(contentView, NSLayoutAttributeTop, - NSLayoutRelationEqual, - childView, NSLayoutAttributeTop, - 1, -margin, - [desc stringByAppendingString:@" top constraint"]); - [contentView addConstraint:c->topConstraint]; - [c->topConstraint retain]; - - c->trailingConstraintGreater = mkConstraint(contentView, NSLayoutAttributeTrailing, - NSLayoutRelationGreaterThanOrEqual, - childView, NSLayoutAttributeTrailing, - 1, margin, - [desc stringByAppendingString:@" trailing >= constraint"]); - if (hugsTrailing) - [c->trailingConstraintGreater setPriority:NSLayoutPriorityDefaultLow]; - [contentView addConstraint:c->trailingConstraintGreater]; - [c->trailingConstraintGreater retain]; - - c->trailingConstraintEqual = mkConstraint(contentView, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - childView, NSLayoutAttributeTrailing, - 1, margin, - [desc stringByAppendingString:@" trailing == constraint"]); - if (!hugsTrailing) - [c->trailingConstraintEqual setPriority:NSLayoutPriorityDefaultLow]; - [contentView addConstraint:c->trailingConstraintEqual]; - [c->trailingConstraintEqual retain]; - - c->bottomConstraintGreater = mkConstraint(contentView, NSLayoutAttributeBottom, - NSLayoutRelationGreaterThanOrEqual, - childView, NSLayoutAttributeBottom, - 1, margin, - [desc stringByAppendingString:@" bottom >= constraint"]); - if (hugsBottom) - [c->bottomConstraintGreater setPriority:NSLayoutPriorityDefaultLow]; - [contentView addConstraint:c->bottomConstraintGreater]; - [c->bottomConstraintGreater retain]; - - c->bottomConstraintEqual = mkConstraint(contentView, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - childView, NSLayoutAttributeBottom, - 1, margin, - [desc stringByAppendingString:@" bottom == constraint"]); - if (!hugsBottom) - [c->bottomConstraintEqual setPriority:NSLayoutPriorityDefaultLow]; - [contentView addConstraint:c->bottomConstraintEqual]; - [c->bottomConstraintEqual retain]; -} - -void singleChildConstraintsRemove(struct singleChildConstraints *c, NSView *cv) -{ - if (c->leadingConstraint != nil) { - [cv removeConstraint:c->leadingConstraint]; - [c->leadingConstraint release]; - c->leadingConstraint = nil; - } - if (c->topConstraint != nil) { - [cv removeConstraint:c->topConstraint]; - [c->topConstraint release]; - c->topConstraint = nil; - } - if (c->trailingConstraintGreater != nil) { - [cv removeConstraint:c->trailingConstraintGreater]; - [c->trailingConstraintGreater release]; - c->trailingConstraintGreater = nil; - } - if (c->trailingConstraintEqual != nil) { - [cv removeConstraint:c->trailingConstraintEqual]; - [c->trailingConstraintEqual release]; - c->trailingConstraintEqual = nil; - } - if (c->bottomConstraintGreater != nil) { - [cv removeConstraint:c->bottomConstraintGreater]; - [c->bottomConstraintGreater release]; - c->bottomConstraintGreater = nil; - } - if (c->bottomConstraintEqual != nil) { - [cv removeConstraint:c->bottomConstraintEqual]; - [c->bottomConstraintEqual release]; - c->bottomConstraintEqual = nil; - } -} - -void singleChildConstraintsSetMargined(struct singleChildConstraints *c, int margined) -{ - CGFloat margin; - - margin = margins(margined); - if (c->leadingConstraint != nil) - [c->leadingConstraint setConstant:-margin]; - if (c->topConstraint != nil) - [c->topConstraint setConstant:-margin]; - if (c->trailingConstraintGreater != nil) - [c->trailingConstraintGreater setConstant:margin]; - if (c->trailingConstraintEqual != nil) - [c->trailingConstraintEqual setConstant:margin]; - if (c->bottomConstraintGreater != nil) - [c->bottomConstraintGreater setConstant:margin]; - if (c->bottomConstraintEqual != nil) - [c->bottomConstraintEqual setConstant:margin]; -} diff --git a/deps/libui/darwin/box.m b/deps/libui/darwin/box.m deleted file mode 100644 index 18d536d5ac..0000000000 --- a/deps/libui/darwin/box.m +++ /dev/null @@ -1,469 +0,0 @@ -// 15 august 2015 -#import "uipriv_darwin.h" - -// TODO hiding all stretchy controls still hugs trailing edge - -@interface boxChild : NSObject -@property uiControl *c; -@property BOOL stretchy; -@property NSLayoutPriority oldPrimaryHuggingPri; -@property NSLayoutPriority oldSecondaryHuggingPri; -- (NSView *)view; -@end - -@interface boxView : NSView { - uiBox *b; - NSMutableArray *children; - BOOL vertical; - int padded; - - NSLayoutConstraint *first; - NSMutableArray *inBetweens; - NSLayoutConstraint *last; - NSMutableArray *otherConstraints; - - NSLayoutAttribute primaryStart; - NSLayoutAttribute primaryEnd; - NSLayoutAttribute secondaryStart; - NSLayoutAttribute secondaryEnd; - NSLayoutAttribute primarySize; - NSLayoutConstraintOrientation primaryOrientation; - NSLayoutConstraintOrientation secondaryOrientation; -} -- (id)initWithVertical:(BOOL)vert b:(uiBox *)bb; -- (void)onDestroy; -- (void)removeOurConstraints; -- (void)syncEnableStates:(int)enabled; -- (CGFloat)paddingAmount; -- (void)establishOurConstraints; -- (void)append:(uiControl *)c stretchy:(int)stretchy; -- (void)delete:(int)n; -- (int)isPadded; -- (void)setPadded:(int)p; -- (BOOL)hugsTrailing; -- (BOOL)hugsBottom; -- (int)nStretchy; -@end - -struct uiBox { - uiDarwinControl c; - boxView *view; -}; - -@implementation boxChild - -- (NSView *)view -{ - return (NSView *) uiControlHandle(self.c); -} - -@end - -@implementation boxView - -- (id)initWithVertical:(BOOL)vert b:(uiBox *)bb -{ - self = [super initWithFrame:NSZeroRect]; - if (self != nil) { - // the weird names vert and bb are to shut the compiler up about shadowing because implicit this/self is stupid - self->b = bb; - self->vertical = vert; - self->padded = 0; - self->children = [NSMutableArray new]; - - self->inBetweens = [NSMutableArray new]; - self->otherConstraints = [NSMutableArray new]; - - if (self->vertical) { - self->primaryStart = NSLayoutAttributeTop; - self->primaryEnd = NSLayoutAttributeBottom; - self->secondaryStart = NSLayoutAttributeLeading; - self->secondaryEnd = NSLayoutAttributeTrailing; - self->primarySize = NSLayoutAttributeHeight; - self->primaryOrientation = NSLayoutConstraintOrientationVertical; - self->secondaryOrientation = NSLayoutConstraintOrientationHorizontal; - } else { - self->primaryStart = NSLayoutAttributeLeading; - self->primaryEnd = NSLayoutAttributeTrailing; - self->secondaryStart = NSLayoutAttributeTop; - self->secondaryEnd = NSLayoutAttributeBottom; - self->primarySize = NSLayoutAttributeWidth; - self->primaryOrientation = NSLayoutConstraintOrientationHorizontal; - self->secondaryOrientation = NSLayoutConstraintOrientationVertical; - } - } - return self; -} - -- (void)onDestroy -{ - boxChild *bc; - - [self removeOurConstraints]; - [self->inBetweens release]; - [self->otherConstraints release]; - - for (bc in self->children) { - uiControlSetParent(bc.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(bc.c), nil); - uiControlDestroy(bc.c); - } - [self->children release]; -} - -- (void)removeOurConstraints -{ - if (self->first != nil) { - [self removeConstraint:self->first]; - [self->first release]; - self->first = nil; - } - if ([self->inBetweens count] != 0) { - [self removeConstraints:self->inBetweens]; - [self->inBetweens removeAllObjects]; - } - if (self->last != nil) { - [self removeConstraint:self->last]; - [self->last release]; - self->last = nil; - } - if ([self->otherConstraints count] != 0) { - [self removeConstraints:self->otherConstraints]; - [self->otherConstraints removeAllObjects]; - } -} - -- (void)syncEnableStates:(int)enabled -{ - boxChild *bc; - - for (bc in self->children) - uiDarwinControlSyncEnableState(uiDarwinControl(bc.c), enabled); -} - -- (CGFloat)paddingAmount -{ - if (!self->padded) - return 0.0; - return uiDarwinPaddingAmount(NULL); -} - -- (void)establishOurConstraints -{ - boxChild *bc; - CGFloat padding; - NSView *prev; - NSLayoutConstraint *c; - BOOL (*hugsSecondary)(uiDarwinControl *); - - [self removeOurConstraints]; - if ([self->children count] == 0) - return; - padding = [self paddingAmount]; - - // first arrange in the primary direction - prev = nil; - for (bc in self->children) { - if (!uiControlVisible(bc.c)) - continue; - if (prev == nil) { // first view - self->first = mkConstraint(self, self->primaryStart, - NSLayoutRelationEqual, - [bc view], self->primaryStart, - 1, 0, - @"uiBox first primary constraint"); - [self addConstraint:self->first]; - [self->first retain]; - prev = [bc view]; - continue; - } - // not the first; link it - c = mkConstraint(prev, self->primaryEnd, - NSLayoutRelationEqual, - [bc view], self->primaryStart, - 1, -padding, - @"uiBox in-between primary constraint"); - [self addConstraint:c]; - [self->inBetweens addObject:c]; - prev = [bc view]; - } - if (prev == nil) // no control visible; act as if no controls - return; - self->last = mkConstraint(prev, self->primaryEnd, - NSLayoutRelationEqual, - self, self->primaryEnd, - 1, 0, - @"uiBox last primary constraint"); - [self addConstraint:self->last]; - [self->last retain]; - - // then arrange in the secondary direction - hugsSecondary = uiDarwinControlHugsTrailingEdge; - if (!self->vertical) - hugsSecondary = uiDarwinControlHugsBottom; - for (bc in self->children) { - if (!uiControlVisible(bc.c)) - continue; - c = mkConstraint(self, self->secondaryStart, - NSLayoutRelationEqual, - [bc view], self->secondaryStart, - 1, 0, - @"uiBox secondary start constraint"); - [self addConstraint:c]; - [self->otherConstraints addObject:c]; - c = mkConstraint([bc view], self->secondaryEnd, - NSLayoutRelationLessThanOrEqual, - self, self->secondaryEnd, - 1, 0, - @"uiBox secondary end <= constraint"); - if ((*hugsSecondary)(uiDarwinControl(bc.c))) - [c setPriority:NSLayoutPriorityDefaultLow]; - [self addConstraint:c]; - [self->otherConstraints addObject:c]; - c = mkConstraint([bc view], self->secondaryEnd, - NSLayoutRelationEqual, - self, self->secondaryEnd, - 1, 0, - @"uiBox secondary end == constraint"); - if (!(*hugsSecondary)(uiDarwinControl(bc.c))) - [c setPriority:NSLayoutPriorityDefaultLow]; - [self addConstraint:c]; - [self->otherConstraints addObject:c]; - } - - // and make all stretchy controls the same size - if ([self nStretchy] == 0) - return; - prev = nil; // first stretchy view - for (bc in self->children) { - if (!uiControlVisible(bc.c)) - continue; - if (!bc.stretchy) - continue; - if (prev == nil) { - prev = [bc view]; - continue; - } - c = mkConstraint(prev, self->primarySize, - NSLayoutRelationEqual, - [bc view], self->primarySize, - 1, 0, - @"uiBox stretchy size constraint"); - [self addConstraint:c]; - [self->otherConstraints addObject:c]; - } -} - -- (void)append:(uiControl *)c stretchy:(int)stretchy -{ - boxChild *bc; - NSLayoutPriority priority; - int oldnStretchy; - - bc = [boxChild new]; - bc.c = c; - bc.stretchy = stretchy; - bc.oldPrimaryHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(bc.c), self->primaryOrientation); - bc.oldSecondaryHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(bc.c), self->secondaryOrientation); - - uiControlSetParent(bc.c, uiControl(self->b)); - uiDarwinControlSetSuperview(uiDarwinControl(bc.c), self); - uiDarwinControlSyncEnableState(uiDarwinControl(bc.c), uiControlEnabledToUser(uiControl(self->b))); - - // if a control is stretchy, it should not hug in the primary direction - // otherwise, it should *forcibly* hug - if (bc.stretchy) - priority = NSLayoutPriorityDefaultLow; - else - // LONGTERM will default high work? - priority = NSLayoutPriorityRequired; - uiDarwinControlSetHuggingPriority(uiDarwinControl(bc.c), priority, self->primaryOrientation); - // make sure controls don't hug their secondary direction so they fill the width of the view - uiDarwinControlSetHuggingPriority(uiDarwinControl(bc.c), NSLayoutPriorityDefaultLow, self->secondaryOrientation); - - oldnStretchy = [self nStretchy]; - [self->children addObject:bc]; - - [self establishOurConstraints]; - if (bc.stretchy) - if (oldnStretchy == 0) - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(self->b)); - - [bc release]; // we don't need the initial reference now -} - -- (void)delete:(int)n -{ - boxChild *bc; - int stretchy; - - bc = (boxChild *) [self->children objectAtIndex:n]; - stretchy = bc.stretchy; - - uiControlSetParent(bc.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(bc.c), nil); - - uiDarwinControlSetHuggingPriority(uiDarwinControl(bc.c), bc.oldPrimaryHuggingPri, self->primaryOrientation); - uiDarwinControlSetHuggingPriority(uiDarwinControl(bc.c), bc.oldSecondaryHuggingPri, self->secondaryOrientation); - - [self->children removeObjectAtIndex:n]; - - [self establishOurConstraints]; - if (stretchy) - if ([self nStretchy] == 0) - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(self->b)); -} - -- (int)isPadded -{ - return self->padded; -} - -- (void)setPadded:(int)p -{ - CGFloat padding; - NSLayoutConstraint *c; - - self->padded = p; - padding = [self paddingAmount]; - for (c in self->inBetweens) - [c setConstant:-padding]; -} - -- (BOOL)hugsTrailing -{ - if (self->vertical) // always hug if vertical - return YES; - return [self nStretchy] != 0; -} - -- (BOOL)hugsBottom -{ - if (!self->vertical) // always hug if horizontal - return YES; - return [self nStretchy] != 0; -} - -- (int)nStretchy -{ - boxChild *bc; - int n; - - n = 0; - for (bc in self->children) { - if (!uiControlVisible(bc.c)) - continue; - if (bc.stretchy) - n++; - } - return n; -} - -@end - -static void uiBoxDestroy(uiControl *c) -{ - uiBox *b = uiBox(c); - - [b->view onDestroy]; - [b->view release]; - uiFreeControl(uiControl(b)); -} - -uiDarwinControlDefaultHandle(uiBox, view) -uiDarwinControlDefaultParent(uiBox, view) -uiDarwinControlDefaultSetParent(uiBox, view) -uiDarwinControlDefaultToplevel(uiBox, view) -uiDarwinControlDefaultVisible(uiBox, view) -uiDarwinControlDefaultShow(uiBox, view) -uiDarwinControlDefaultHide(uiBox, view) -uiDarwinControlDefaultEnabled(uiBox, view) -uiDarwinControlDefaultEnable(uiBox, view) -uiDarwinControlDefaultDisable(uiBox, view) - -static void uiBoxSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiBox *b = uiBox(c); - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(b), enabled)) - return; - [b->view syncEnableStates:enabled]; -} - -uiDarwinControlDefaultSetSuperview(uiBox, view) - -static BOOL uiBoxHugsTrailingEdge(uiDarwinControl *c) -{ - uiBox *b = uiBox(c); - - return [b->view hugsTrailing]; -} - -static BOOL uiBoxHugsBottom(uiDarwinControl *c) -{ - uiBox *b = uiBox(c); - - return [b->view hugsBottom]; -} - -static void uiBoxChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiBox *b = uiBox(c); - - [b->view establishOurConstraints]; -} - -uiDarwinControlDefaultHuggingPriority(uiBox, view) -uiDarwinControlDefaultSetHuggingPriority(uiBox, view) - -static void uiBoxChildVisibilityChanged(uiDarwinControl *c) -{ - uiBox *b = uiBox(c); - - [b->view establishOurConstraints]; -} - -void uiBoxAppend(uiBox *b, uiControl *c, int stretchy) -{ - // LONGTERM on other platforms - // or at leat allow this and implicitly turn it into a spacer - if (c == NULL) - userbug("You cannot add NULL to a uiBox."); - [b->view append:c stretchy:stretchy]; -} - -void uiBoxDelete(uiBox *b, int n) -{ - [b->view delete:n]; -} - -int uiBoxPadded(uiBox *b) -{ - return [b->view isPadded]; -} - -void uiBoxSetPadded(uiBox *b, int padded) -{ - [b->view setPadded:padded]; -} - -static uiBox *finishNewBox(BOOL vertical) -{ - uiBox *b; - - uiDarwinNewControl(uiBox, b); - - b->view = [[boxView alloc] initWithVertical:vertical b:b]; - - return b; -} - -uiBox *uiNewHorizontalBox(void) -{ - return finishNewBox(NO); -} - -uiBox *uiNewVerticalBox(void) -{ - return finishNewBox(YES); -} diff --git a/deps/libui/darwin/button.m b/deps/libui/darwin/button.m deleted file mode 100644 index baccabbb38..0000000000 --- a/deps/libui/darwin/button.m +++ /dev/null @@ -1,113 +0,0 @@ -// 13 august 2015 -#import "uipriv_darwin.h" - -struct uiButton { - uiDarwinControl c; - NSButton *button; - void (*onClicked)(uiButton *, void *); - void *onClickedData; -}; - -@interface buttonDelegateClass : NSObject { - struct mapTable *buttons; -} -- (IBAction)onClicked:(id)sender; -- (void)registerButton:(uiButton *)b; -- (void)unregisterButton:(uiButton *)b; -@end - -@implementation buttonDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->buttons = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->buttons); - [super dealloc]; -} - -- (IBAction)onClicked:(id)sender -{ - uiButton *b; - - b = (uiButton *) mapGet(self->buttons, sender); - (*(b->onClicked))(b, b->onClickedData); -} - -- (void)registerButton:(uiButton *)b -{ - mapSet(self->buttons, b->button, b); - [b->button setTarget:self]; - [b->button setAction:@selector(onClicked:)]; -} - -- (void)unregisterButton:(uiButton *)b -{ - [b->button setTarget:nil]; - mapDelete(self->buttons, b->button); -} - -@end - -static buttonDelegateClass *buttonDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiButton, button) - -static void uiButtonDestroy(uiControl *c) -{ - uiButton *b = uiButton(c); - - [buttonDelegate unregisterButton:b]; - [b->button release]; - uiFreeControl(uiControl(b)); -} - -char *uiButtonText(uiButton *b) -{ - return uiDarwinNSStringToText([b->button title]); -} - -void uiButtonSetText(uiButton *b, const char *text) -{ - [b->button setTitle:toNSString(text)]; -} - -void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *, void *), void *data) -{ - b->onClicked = f; - b->onClickedData = data; -} - -static void defaultOnClicked(uiButton *b, void *data) -{ - // do nothing -} - -uiButton *uiNewButton(const char *text) -{ - uiButton *b; - - uiDarwinNewControl(uiButton, b); - - b->button = [[NSButton alloc] initWithFrame:NSZeroRect]; - [b->button setTitle:toNSString(text)]; - [b->button setButtonType:NSMomentaryPushInButton]; - [b->button setBordered:YES]; - [b->button setBezelStyle:NSRoundedBezelStyle]; - uiDarwinSetControlFont(b->button, NSRegularControlSize); - - if (buttonDelegate == nil) { - buttonDelegate = [[buttonDelegateClass new] autorelease]; - [delegates addObject:buttonDelegate]; - } - [buttonDelegate registerButton:b]; - uiButtonOnClicked(b, defaultOnClicked, NULL); - - return b; -} diff --git a/deps/libui/darwin/checkbox.m b/deps/libui/darwin/checkbox.m deleted file mode 100644 index dd1ce09357..0000000000 --- a/deps/libui/darwin/checkbox.m +++ /dev/null @@ -1,129 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -struct uiCheckbox { - uiDarwinControl c; - NSButton *button; - void (*onToggled)(uiCheckbox *, void *); - void *onToggledData; -}; - -@interface checkboxDelegateClass : NSObject { - struct mapTable *buttons; -} -- (IBAction)onToggled:(id)sender; -- (void)registerCheckbox:(uiCheckbox *)c; -- (void)unregisterCheckbox:(uiCheckbox *)c; -@end - -@implementation checkboxDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->buttons = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->buttons); - [super dealloc]; -} - -- (IBAction)onToggled:(id)sender -{ - uiCheckbox *c; - - c = (uiCheckbox *) mapGet(self->buttons, sender); - (*(c->onToggled))(c, c->onToggledData); -} - -- (void)registerCheckbox:(uiCheckbox *)c -{ - mapSet(self->buttons, c->button, c); - [c->button setTarget:self]; - [c->button setAction:@selector(onToggled:)]; -} - -- (void)unregisterCheckbox:(uiCheckbox *)c -{ - [c->button setTarget:nil]; - mapDelete(self->buttons, c->button); -} - -@end - -static checkboxDelegateClass *checkboxDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiCheckbox, button) - -static void uiCheckboxDestroy(uiControl *cc) -{ - uiCheckbox *c = uiCheckbox(cc); - - [checkboxDelegate unregisterCheckbox:c]; - [c->button release]; - uiFreeControl(uiControl(c)); -} - -char *uiCheckboxText(uiCheckbox *c) -{ - return uiDarwinNSStringToText([c->button title]); -} - -void uiCheckboxSetText(uiCheckbox *c, const char *text) -{ - [c->button setTitle:toNSString(text)]; -} - -void uiCheckboxOnToggled(uiCheckbox *c, void (*f)(uiCheckbox *, void *), void *data) -{ - c->onToggled = f; - c->onToggledData = data; -} - -int uiCheckboxChecked(uiCheckbox *c) -{ - return [c->button state] == NSOnState; -} - -void uiCheckboxSetChecked(uiCheckbox *c, int checked) -{ - NSInteger state; - - state = NSOnState; - if (!checked) - state = NSOffState; - [c->button setState:state]; -} - -static void defaultOnToggled(uiCheckbox *c, void *data) -{ - // do nothing -} - -uiCheckbox *uiNewCheckbox(const char *text) -{ - uiCheckbox *c; - - uiDarwinNewControl(uiCheckbox, c); - - c->button = [[NSButton alloc] initWithFrame:NSZeroRect]; - [c->button setTitle:toNSString(text)]; - [c->button setButtonType:NSSwitchButton]; - // doesn't seem to have an associated bezel style - [c->button setBordered:NO]; - [c->button setTransparent:NO]; - uiDarwinSetControlFont(c->button, NSRegularControlSize); - - if (checkboxDelegate == nil) { - checkboxDelegate = [[checkboxDelegateClass new] autorelease]; - [delegates addObject:checkboxDelegate]; - } - [checkboxDelegate registerCheckbox:c]; - uiCheckboxOnToggled(c, defaultOnToggled, NULL); - - return c; -} diff --git a/deps/libui/darwin/colorbutton.m b/deps/libui/darwin/colorbutton.m deleted file mode 100644 index 83b61571eb..0000000000 --- a/deps/libui/darwin/colorbutton.m +++ /dev/null @@ -1,159 +0,0 @@ -// 15 may 2016 -#import "uipriv_darwin.h" - -// TODO no intrinsic height? - -@interface colorButton : NSColorWell { - uiColorButton *libui_b; - BOOL libui_changing; - BOOL libui_setting; -} -- (id)initWithFrame:(NSRect)frame libuiColorButton:(uiColorButton *)b; -- (void)deactivateOnClose:(NSNotification *)note; -- (void)libuiColor:(double *)r g:(double *)g b:(double *)b a:(double *)a; -- (void)libuiSetColor:(double)r g:(double)g b:(double)b a:(double)a; -@end - -// only one may be active at one time -static colorButton *activeColorButton = nil; - -struct uiColorButton { - uiDarwinControl c; - colorButton *button; - void (*onChanged)(uiColorButton *, void *); - void *onChangedData; -}; - -@implementation colorButton - -- (id)initWithFrame:(NSRect)frame libuiColorButton:(uiColorButton *)b -{ - self = [super initWithFrame:frame]; - if (self) { - // the default color is white; set it to black first (see -setColor: below for why we do it first) - [self libuiSetColor:0.0 g:0.0 b:0.0 a:1.0]; - - self->libui_b = b; - self->libui_changing = NO; - } - return self; -} - -- (void)activate:(BOOL)exclusive -{ - if (activeColorButton != nil) - activeColorButton->libui_changing = YES; - [NSColorPanel setPickerMask:NSColorPanelAllModesMask]; - [[NSColorPanel sharedColorPanel] setShowsAlpha:YES]; - [super activate:YES]; - activeColorButton = self; - // see stddialogs.m for details - [[NSColorPanel sharedColorPanel] setWorksWhenModal:NO]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(deactivateOnClose:) - name:NSWindowWillCloseNotification - object:[NSColorPanel sharedColorPanel]]; -} - -- (void)deactivate -{ - [super deactivate]; - activeColorButton = nil; - if (!self->libui_changing) - [[NSColorPanel sharedColorPanel] orderOut:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSWindowWillCloseNotification - object:[NSColorPanel sharedColorPanel]]; - self->libui_changing = NO; -} - -- (void)deactivateOnClose:(NSNotification *)note -{ - [self deactivate]; -} - -- (void)setColor:(NSColor *)color -{ - uiColorButton *b = self->libui_b; - - [super setColor:color]; - // this is called by NSColorWell's init, so we have to guard - // also don't signal during a programmatic change - if (b != nil && !self->libui_setting) - (*(b->onChanged))(b, b->onChangedData); -} - -- (void)libuiColor:(double *)r g:(double *)g b:(double *)b a:(double *)a -{ - NSColor *rgba; - CGFloat cr, cg, cb, ca; - - // the given color may not be an RGBA color, which will cause the -getRed:green:blue:alpha: call to throw an exception - rgba = [[self color] colorUsingColorSpace:[NSColorSpace sRGBColorSpace]]; - [rgba getRed:&cr green:&cg blue:&cb alpha:&ca]; - *r = cr; - *g = cg; - *b = cb; - *a = ca; - // rgba will be autoreleased since it isn't a new or init call -} - -- (void)libuiSetColor:(double)r g:(double)g b:(double)b a:(double)a -{ - self->libui_setting = YES; - [self setColor:[NSColor colorWithSRGBRed:r green:g blue:b alpha:a]]; - self->libui_setting = NO; -} - -// NSColorWell has no intrinsic size by default; give it the default Interface Builder size. -- (NSSize)intrinsicContentSize -{ - return NSMakeSize(44, 23); -} - -@end - -uiDarwinControlAllDefaults(uiColorButton, button) - -// we do not want color change events to be sent to any controls other than the color buttons -// see main.m for more details -BOOL colorButtonInhibitSendAction(SEL sel, id from, id to) -{ - if (sel != @selector(changeColor:)) - return NO; - return ![to isKindOfClass:[colorButton class]]; -} - -static void defaultOnChanged(uiColorButton *b, void *data) -{ - // do nothing -} - -void uiColorButtonColor(uiColorButton *b, double *r, double *g, double *bl, double *a) -{ - [b->button libuiColor:r g:g b:bl a:a]; -} - -void uiColorButtonSetColor(uiColorButton *b, double r, double g, double bl, double a) -{ - [b->button libuiSetColor:r g:g b:bl a:a]; -} - -void uiColorButtonOnChanged(uiColorButton *b, void (*f)(uiColorButton *, void *), void *data) -{ - b->onChanged = f; - b->onChangedData = data; -} - -uiColorButton *uiNewColorButton(void) -{ - uiColorButton *b; - - uiDarwinNewControl(uiColorButton, b); - - b->button = [[colorButton alloc] initWithFrame:NSZeroRect libuiColorButton:b]; - - uiColorButtonOnChanged(b, defaultOnChanged, NULL); - - return b; -} diff --git a/deps/libui/darwin/combobox.m b/deps/libui/darwin/combobox.m deleted file mode 100644 index 89a2e28cb8..0000000000 --- a/deps/libui/darwin/combobox.m +++ /dev/null @@ -1,145 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// NSComboBoxes have no intrinsic width; we'll use the default Interface Builder width for them. -// NSPopUpButton is fine. -#define comboboxWidth 96 - -struct uiCombobox { - uiDarwinControl c; - NSPopUpButton *pb; - NSArrayController *pbac; - void (*onSelected)(uiCombobox *, void *); - void *onSelectedData; -}; - -@interface comboboxDelegateClass : NSObject { - struct mapTable *comboboxes; -} -- (IBAction)onSelected:(id)sender; -- (void)registerCombobox:(uiCombobox *)c; -- (void)unregisterCombobox:(uiCombobox *)c; -@end - -@implementation comboboxDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->comboboxes = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->comboboxes); - [super dealloc]; -} - -- (IBAction)onSelected:(id)sender -{ - uiCombobox *c; - - c = uiCombobox(mapGet(self->comboboxes, sender)); - (*(c->onSelected))(c, c->onSelectedData); -} - -- (void)registerCombobox:(uiCombobox *)c -{ - mapSet(self->comboboxes, c->pb, c); - [c->pb setTarget:self]; - [c->pb setAction:@selector(onSelected:)]; -} - -- (void)unregisterCombobox:(uiCombobox *)c -{ - [c->pb setTarget:nil]; - mapDelete(self->comboboxes, c->pb); -} - -@end - -static comboboxDelegateClass *comboboxDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiCombobox, pb) - -static void uiComboboxDestroy(uiControl *cc) -{ - uiCombobox *c = uiCombobox(cc); - - [comboboxDelegate unregisterCombobox:c]; - [c->pb unbind:@"contentObjects"]; - [c->pb unbind:@"selectedIndex"]; - [c->pbac release]; - [c->pb release]; - uiFreeControl(uiControl(c)); -} - -void uiComboboxAppend(uiCombobox *c, const char *text) -{ - [c->pbac addObject:toNSString(text)]; -} - -int uiComboboxSelected(uiCombobox *c) -{ - return [c->pb indexOfSelectedItem]; -} - -void uiComboboxSetSelected(uiCombobox *c, int n) -{ - [c->pb selectItemAtIndex:n]; -} - -void uiComboboxOnSelected(uiCombobox *c, void (*f)(uiCombobox *c, void *data), void *data) -{ - c->onSelected = f; - c->onSelectedData = data; -} - -static void defaultOnSelected(uiCombobox *c, void *data) -{ - // do nothing -} - -uiCombobox *uiNewCombobox(void) -{ - uiCombobox *c; - NSPopUpButtonCell *pbcell; - - uiDarwinNewControl(uiCombobox, c); - - c->pb = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO]; - [c->pb setPreferredEdge:NSMinYEdge]; - pbcell = (NSPopUpButtonCell *) [c->pb cell]; - [pbcell setArrowPosition:NSPopUpArrowAtBottom]; - // the font defined by Interface Builder is Menu 13, which is lol - // just use the regular control size for consistency - uiDarwinSetControlFont(c->pb, NSRegularControlSize); - - // NSPopUpButton doesn't work like a combobox - // - it automatically selects the first item - // - it doesn't support duplicates - // but we can use a NSArrayController and Cocoa bindings to bypass these restrictions - c->pbac = [NSArrayController new]; - [c->pbac setAvoidsEmptySelection:NO]; - [c->pbac setSelectsInsertedObjects:NO]; - [c->pbac setAutomaticallyRearrangesObjects:NO]; - [c->pb bind:@"contentValues" - toObject:c->pbac - withKeyPath:@"arrangedObjects" - options:nil]; - [c->pb bind:@"selectedIndex" - toObject:c->pbac - withKeyPath:@"selectionIndex" - options:nil]; - - if (comboboxDelegate == nil) { - comboboxDelegate = [[comboboxDelegateClass new] autorelease]; - [delegates addObject:comboboxDelegate]; - } - [comboboxDelegate registerCombobox:c]; - uiComboboxOnSelected(c, defaultOnSelected, NULL); - - return c; -} diff --git a/deps/libui/darwin/control.m b/deps/libui/darwin/control.m deleted file mode 100644 index 9eaf47a274..0000000000 --- a/deps/libui/darwin/control.m +++ /dev/null @@ -1,84 +0,0 @@ -// 16 august 2015 -#import "uipriv_darwin.h" - -void uiDarwinControlSyncEnableState(uiDarwinControl *c, int state) -{ - (*(c->SyncEnableState))(c, state); -} - -void uiDarwinControlSetSuperview(uiDarwinControl *c, NSView *superview) -{ - (*(c->SetSuperview))(c, superview); -} - -BOOL uiDarwinControlHugsTrailingEdge(uiDarwinControl *c) -{ - return (*(c->HugsTrailingEdge))(c); -} - -BOOL uiDarwinControlHugsBottom(uiDarwinControl *c) -{ - return (*(c->HugsBottom))(c); -} - -void uiDarwinControlChildEdgeHuggingChanged(uiDarwinControl *c) -{ - (*(c->ChildEdgeHuggingChanged))(c); -} - -NSLayoutPriority uiDarwinControlHuggingPriority(uiDarwinControl *c, NSLayoutConstraintOrientation orientation) -{ - return (*(c->HuggingPriority))(c, orientation); -} - -void uiDarwinControlSetHuggingPriority(uiDarwinControl *c, NSLayoutPriority priority, NSLayoutConstraintOrientation orientation) -{ - (*(c->SetHuggingPriority))(c, priority, orientation); -} - -void uiDarwinControlChildVisibilityChanged(uiDarwinControl *c) -{ - (*(c->ChildVisibilityChanged))(c); -} - -void uiDarwinSetControlFont(NSControl *c, NSControlSize size) -{ - [c setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:size]]]; -} - -#define uiDarwinControlSignature 0x44617277 - -uiDarwinControl *uiDarwinAllocControl(size_t n, uint32_t typesig, const char *typenamestr) -{ - return uiDarwinControl(uiAllocControl(n, uiDarwinControlSignature, typesig, typenamestr)); -} - -BOOL uiDarwinShouldStopSyncEnableState(uiDarwinControl *c, BOOL enabled) -{ - int ce; - - ce = uiControlEnabled(uiControl(c)); - // only stop if we're going from disabled back to enabled; don't stop under any other condition - // (if we stop when going from enabled to disabled then enabled children of a disabled control won't get disabled at the OS level) - if (!ce && enabled) - return YES; - return NO; -} - -void uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl *c) -{ - uiControl *parent; - - parent = uiControlParent(uiControl(c)); - if (parent != NULL) - uiDarwinControlChildEdgeHuggingChanged(uiDarwinControl(parent)); -} - -void uiDarwinNotifyVisibilityChanged(uiDarwinControl *c) -{ - uiControl *parent; - - parent = uiControlParent(uiControl(c)); - if (parent != NULL) - uiDarwinControlChildVisibilityChanged(uiDarwinControl(parent)); -} diff --git a/deps/libui/darwin/datetimepicker.m b/deps/libui/darwin/datetimepicker.m deleted file mode 100644 index 44364d9d03..0000000000 --- a/deps/libui/darwin/datetimepicker.m +++ /dev/null @@ -1,42 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -struct uiDateTimePicker { - uiDarwinControl c; - NSDatePicker *dp; -}; - -uiDarwinControlAllDefaults(uiDateTimePicker, dp) - -static uiDateTimePicker *finishNewDateTimePicker(NSDatePickerElementFlags elements) -{ - uiDateTimePicker *d; - - uiDarwinNewControl(uiDateTimePicker, d); - - d->dp = [[NSDatePicker alloc] initWithFrame:NSZeroRect]; - [d->dp setBordered:NO]; - [d->dp setBezeled:YES]; - [d->dp setDrawsBackground:YES]; - [d->dp setDatePickerStyle:NSTextFieldAndStepperDatePickerStyle]; - [d->dp setDatePickerElements:elements]; - [d->dp setDatePickerMode:NSSingleDateMode]; - uiDarwinSetControlFont(d->dp, NSRegularControlSize); - - return d; -} - -uiDateTimePicker *uiNewDateTimePicker(void) -{ - return finishNewDateTimePicker(NSYearMonthDayDatePickerElementFlag | NSHourMinuteSecondDatePickerElementFlag); -} - -uiDateTimePicker *uiNewDatePicker(void) -{ - return finishNewDateTimePicker(NSYearMonthDayDatePickerElementFlag); -} - -uiDateTimePicker *uiNewTimePicker(void) -{ - return finishNewDateTimePicker(NSHourMinuteSecondDatePickerElementFlag); -} diff --git a/deps/libui/darwin/debug.m b/deps/libui/darwin/debug.m deleted file mode 100644 index c91c6a738f..0000000000 --- a/deps/libui/darwin/debug.m +++ /dev/null @@ -1,19 +0,0 @@ -// 13 may 2016 -#import "uipriv_darwin.h" - -// LONGTERM don't halt on release builds - -void realbug(const char *file, const char *line, const char *func, const char *prefix, const char *format, va_list ap) -{ - NSMutableString *str; - NSString *formatted; - - str = [NSMutableString new]; - [str appendString:[NSString stringWithFormat:@"[libui] %s:%s:%s() %s", file, line, func, prefix]]; - formatted = [[NSString alloc] initWithFormat:[NSString stringWithUTF8String:format] arguments:ap]; - [str appendString:formatted]; - [formatted release]; - NSLog(@"%@", str); - [str release]; - __builtin_trap(); -} diff --git a/deps/libui/darwin/draw.m b/deps/libui/darwin/draw.m deleted file mode 100644 index 262ad3e2b3..0000000000 --- a/deps/libui/darwin/draw.m +++ /dev/null @@ -1,454 +0,0 @@ -// 6 september 2015 -#import "uipriv_darwin.h" - -struct uiDrawPath { - CGMutablePathRef path; - uiDrawFillMode fillMode; - BOOL ended; -}; - -uiDrawPath *uiDrawNewPath(uiDrawFillMode mode) -{ - uiDrawPath *p; - - p = uiNew(uiDrawPath); - p->path = CGPathCreateMutable(); - p->fillMode = mode; - return p; -} - -void uiDrawFreePath(uiDrawPath *p) -{ - CGPathRelease((CGPathRef) (p->path)); - uiFree(p); -} - -void uiDrawPathNewFigure(uiDrawPath *p, double x, double y) -{ - if (p->ended) - userbug("You cannot call uiDrawPathNewFigure() on a uiDrawPath that has already been ended. (path; %p)", p); - CGPathMoveToPoint(p->path, NULL, x, y); -} - -void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative) -{ - double sinStart, cosStart; - double startx, starty; - - if (p->ended) - userbug("You cannot call uiDrawPathNewFigureWithArc() on a uiDrawPath that has already been ended. (path; %p)", p); - sinStart = sin(startAngle); - cosStart = cos(startAngle); - startx = xCenter + radius * cosStart; - starty = yCenter + radius * sinStart; - CGPathMoveToPoint(p->path, NULL, startx, starty); - uiDrawPathArcTo(p, xCenter, yCenter, radius, startAngle, sweep, negative); -} - -void uiDrawPathLineTo(uiDrawPath *p, double x, double y) -{ - // TODO refine this to require being in a path - if (p->ended) - implbug("attempt to add line to ended path in uiDrawPathLineTo()"); - CGPathAddLineToPoint(p->path, NULL, x, y); -} - -void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative) -{ - bool cw; - - // TODO likewise - if (p->ended) - implbug("attempt to add arc to ended path in uiDrawPathArcTo()"); - if (sweep > 2 * uiPi) - sweep = 2 * uiPi; - cw = false; - if (negative) - cw = true; - CGPathAddArc(p->path, NULL, - xCenter, yCenter, - radius, - startAngle, startAngle + sweep, - cw); -} - -void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY) -{ - // TODO likewise - if (p->ended) - implbug("attempt to add bezier to ended path in uiDrawPathBezierTo()"); - CGPathAddCurveToPoint(p->path, NULL, - c1x, c1y, - c2x, c2y, - endX, endY); -} - -void uiDrawPathCloseFigure(uiDrawPath *p) -{ - // TODO likewise - if (p->ended) - implbug("attempt to close figure of ended path in uiDrawPathCloseFigure()"); - CGPathCloseSubpath(p->path); -} - -void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height) -{ - if (p->ended) - userbug("You cannot call uiDrawPathAddRectangle() on a uiDrawPath that has already been ended. (path; %p)", p); - CGPathAddRect(p->path, NULL, CGRectMake(x, y, width, height)); -} - -void uiDrawPathEnd(uiDrawPath *p) -{ - p->ended = TRUE; -} - -struct uiDrawContext { - CGContextRef c; - CGFloat height; // needed for text; see below -}; - -uiDrawContext *newContext(CGContextRef ctxt, CGFloat height) -{ - uiDrawContext *c; - - c = uiNew(uiDrawContext); - c->c = ctxt; - c->height = height; - return c; -} - -void freeContext(uiDrawContext *c) -{ - uiFree(c); -} - -// a stroke is identical to a fill of a stroked path -// we need to do this in order to stroke with a gradient; see http://stackoverflow.com/a/25034854/3408572 -// doing this for other brushes works too -void uiDrawStroke(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b, uiDrawStrokeParams *p) -{ - CGLineCap cap; - CGLineJoin join; - CGPathRef dashPath; - CGFloat *dashes; - size_t i; - uiDrawPath p2; - - if (!path->ended) - userbug("You cannot call uiDrawStroke() on a uiDrawPath that has not been ended. (path: %p)", path); - - switch (p->Cap) { - case uiDrawLineCapFlat: - cap = kCGLineCapButt; - break; - case uiDrawLineCapRound: - cap = kCGLineCapRound; - break; - case uiDrawLineCapSquare: - cap = kCGLineCapSquare; - break; - } - switch (p->Join) { - case uiDrawLineJoinMiter: - join = kCGLineJoinMiter; - break; - case uiDrawLineJoinRound: - join = kCGLineJoinRound; - break; - case uiDrawLineJoinBevel: - join = kCGLineJoinBevel; - break; - } - - // create a temporary path identical to the previous one - dashPath = (CGPathRef) path->path; - if (p->NumDashes != 0) { - dashes = (CGFloat *) uiAlloc(p->NumDashes * sizeof (CGFloat), "CGFloat[]"); - for (i = 0; i < p->NumDashes; i++) - dashes[i] = p->Dashes[i]; - dashPath = CGPathCreateCopyByDashingPath(path->path, - NULL, - p->DashPhase, - dashes, - p->NumDashes); - uiFree(dashes); - } - // the documentation is wrong: this produces a path suitable for calling CGPathCreateCopyByStrokingPath(), not for filling directly - // the cast is safe; we never modify the CGPathRef and always cast it back to a CGPathRef anyway - p2.path = (CGMutablePathRef) CGPathCreateCopyByStrokingPath(dashPath, - NULL, - p->Thickness, - cap, - join, - p->MiterLimit); - if (p->NumDashes != 0) - CGPathRelease(dashPath); - - // always draw stroke fills using the winding rule - // otherwise intersecting figures won't draw correctly - p2.fillMode = uiDrawFillModeWinding; - p2.ended = path->ended; - uiDrawFill(c, &p2, b); - // and clean up - CGPathRelease((CGPathRef) (p2.path)); -} - -// for a solid fill, we can merely have Core Graphics fill directly -static void fillSolid(CGContextRef ctxt, uiDrawPath *p, uiDrawBrush *b) -{ - // TODO this uses DeviceRGB; switch to sRGB - CGContextSetRGBFillColor(ctxt, b->R, b->G, b->B, b->A); - switch (p->fillMode) { - case uiDrawFillModeWinding: - CGContextFillPath(ctxt); - break; - case uiDrawFillModeAlternate: - CGContextEOFillPath(ctxt); - break; - } -} - -// for a gradient fill, we need to clip to the path and then draw the gradient -// see http://stackoverflow.com/a/25034854/3408572 -static void fillGradient(CGContextRef ctxt, uiDrawPath *p, uiDrawBrush *b) -{ - CGGradientRef gradient; - CGColorSpaceRef colorspace; - CGFloat *colors; - CGFloat *locations; - size_t i; - - // gradients need a color space - // for consistency with windows, use sRGB - colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - - // make the gradient - colors = uiAlloc(b->NumStops * 4 * sizeof (CGFloat), "CGFloat[]"); - locations = uiAlloc(b->NumStops * sizeof (CGFloat), "CGFloat[]"); - for (i = 0; i < b->NumStops; i++) { - colors[i * 4 + 0] = b->Stops[i].R; - colors[i * 4 + 1] = b->Stops[i].G; - colors[i * 4 + 2] = b->Stops[i].B; - colors[i * 4 + 3] = b->Stops[i].A; - locations[i] = b->Stops[i].Pos; - } - gradient = CGGradientCreateWithColorComponents(colorspace, colors, locations, b->NumStops); - uiFree(locations); - uiFree(colors); - - // because we're mucking with clipping, we need to save the graphics state and restore it later - CGContextSaveGState(ctxt); - - // clip - switch (p->fillMode) { - case uiDrawFillModeWinding: - CGContextClip(ctxt); - break; - case uiDrawFillModeAlternate: - CGContextEOClip(ctxt); - break; - } - - // draw the gradient - switch (b->Type) { - case uiDrawBrushTypeLinearGradient: - CGContextDrawLinearGradient(ctxt, - gradient, - CGPointMake(b->X0, b->Y0), - CGPointMake(b->X1, b->Y1), - kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); - break; - case uiDrawBrushTypeRadialGradient: - CGContextDrawRadialGradient(ctxt, - gradient, - CGPointMake(b->X0, b->Y0), - // make the start circle radius 0 to make it a point - 0, - CGPointMake(b->X1, b->Y1), - b->OuterRadius, - kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); - break; - } - - // and clean up - CGContextRestoreGState(ctxt); - CGGradientRelease(gradient); - CGColorSpaceRelease(colorspace); -} - -void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b) -{ - if (!path->ended) - userbug("You cannot call uiDrawStroke() on a uiDrawPath that has not been ended. (path: %p)", path); - CGContextAddPath(c->c, (CGPathRef) (path->path)); - switch (b->Type) { - case uiDrawBrushTypeSolid: - fillSolid(c->c, path, b); - return; - case uiDrawBrushTypeLinearGradient: - case uiDrawBrushTypeRadialGradient: - fillGradient(c->c, path, b); - return; -// case uiDrawBrushTypeImage: - // TODO - return; - } - userbug("Unknown brush type %d passed to uiDrawFill().", b->Type); -} - -static void m2c(uiDrawMatrix *m, CGAffineTransform *c) -{ - c->a = m->M11; - c->b = m->M12; - c->c = m->M21; - c->d = m->M22; - c->tx = m->M31; - c->ty = m->M32; -} - -static void c2m(CGAffineTransform *c, uiDrawMatrix *m) -{ - m->M11 = c->a; - m->M12 = c->b; - m->M21 = c->c; - m->M22 = c->d; - m->M31 = c->tx; - m->M32 = c->ty; -} - -void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y) -{ - CGAffineTransform c; - - m2c(m, &c); - c = CGAffineTransformTranslate(c, x, y); - c2m(&c, m); -} - -void uiDrawMatrixScale(uiDrawMatrix *m, double xCenter, double yCenter, double x, double y) -{ - CGAffineTransform c; - double xt, yt; - - m2c(m, &c); - xt = x; - yt = y; - scaleCenter(xCenter, yCenter, &xt, &yt); - c = CGAffineTransformTranslate(c, xt, yt); - c = CGAffineTransformScale(c, x, y); - c = CGAffineTransformTranslate(c, -xt, -yt); - c2m(&c, m); -} - -void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount) -{ - CGAffineTransform c; - - m2c(m, &c); - c = CGAffineTransformTranslate(c, x, y); - c = CGAffineTransformRotate(c, amount); - c = CGAffineTransformTranslate(c, -x, -y); - c2m(&c, m); -} - -void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount) -{ - fallbackSkew(m, x, y, xamount, yamount); -} - -void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src) -{ - CGAffineTransform c; - CGAffineTransform d; - - m2c(dest, &c); - m2c(src, &d); - c = CGAffineTransformConcat(c, d); - c2m(&c, dest); -} - -// there is no test for invertibility; CGAffineTransformInvert() is merely documented as returning the matrix unchanged if it isn't invertible -// therefore, special care must be taken to catch matrices who are their own inverses -// TODO figure out which matrices these are and do so -int uiDrawMatrixInvertible(uiDrawMatrix *m) -{ - CGAffineTransform c, d; - - m2c(m, &c); - d = CGAffineTransformInvert(c); - return CGAffineTransformEqualToTransform(c, d) == false; -} - -int uiDrawMatrixInvert(uiDrawMatrix *m) -{ - CGAffineTransform c, d; - - m2c(m, &c); - d = CGAffineTransformInvert(c); - if (CGAffineTransformEqualToTransform(c, d)) - return 0; - c2m(&d, m); - return 1; -} - -void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y) -{ - CGAffineTransform c; - CGPoint p; - - m2c(m, &c); - p = CGPointApplyAffineTransform(CGPointMake(*x, *y), c); - *x = p.x; - *y = p.y; -} - -void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y) -{ - CGAffineTransform c; - CGSize s; - - m2c(m, &c); - s = CGSizeApplyAffineTransform(CGSizeMake(*x, *y), c); - *x = s.width; - *y = s.height; -} - -void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m) -{ - CGAffineTransform cm; - - m2c(m, &cm); - CGContextConcatCTM(c->c, cm); -} - -void uiDrawClip(uiDrawContext *c, uiDrawPath *path) -{ - if (!path->ended) - userbug("You cannot call uiDrawCilp() on a uiDrawPath that has not been ended. (path: %p)", path); - CGContextAddPath(c->c, (CGPathRef) (path->path)); - switch (path->fillMode) { - case uiDrawFillModeWinding: - CGContextClip(c->c); - break; - case uiDrawFillModeAlternate: - CGContextEOClip(c->c); - break; - } -} - -// TODO figure out what besides transforms these save/restore on all platforms -void uiDrawSave(uiDrawContext *c) -{ - CGContextSaveGState(c->c); -} - -void uiDrawRestore(uiDrawContext *c) -{ - CGContextRestoreGState(c->c); -} - -void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout) -{ - doDrawText(c->c, c->height, x, y, layout); -} diff --git a/deps/libui/darwin/drawtext.m b/deps/libui/darwin/drawtext.m deleted file mode 100644 index c376536a02..0000000000 --- a/deps/libui/darwin/drawtext.m +++ /dev/null @@ -1,655 +0,0 @@ -// 6 september 2015 -#import "uipriv_darwin.h" - -// TODO -#define complain(...) implbug(__VA_ARGS__) - -// TODO double-check that we are properly handling allocation failures (or just toll free bridge from cocoa) -struct uiDrawFontFamilies { - CFArrayRef fonts; -}; - -uiDrawFontFamilies *uiDrawListFontFamilies(void) -{ - uiDrawFontFamilies *ff; - - ff = uiNew(uiDrawFontFamilies); - ff->fonts = CTFontManagerCopyAvailableFontFamilyNames(); - if (ff->fonts == NULL) - implbug("error getting available font names (no reason specified) (TODO)"); - return ff; -} - -int uiDrawFontFamiliesNumFamilies(uiDrawFontFamilies *ff) -{ - return CFArrayGetCount(ff->fonts); -} - -char *uiDrawFontFamiliesFamily(uiDrawFontFamilies *ff, int n) -{ - CFStringRef familystr; - char *family; - - familystr = (CFStringRef) CFArrayGetValueAtIndex(ff->fonts, n); - // toll-free bridge - family = uiDarwinNSStringToText((NSString *) familystr); - // Get Rule means we do not free familystr - return family; -} - -void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff) -{ - CFRelease(ff->fonts); - uiFree(ff); -} - -struct uiDrawTextFont { - CTFontRef f; -}; - -uiDrawTextFont *mkTextFont(CTFontRef f, BOOL retain) -{ - uiDrawTextFont *font; - - font = uiNew(uiDrawTextFont); - font->f = f; - if (retain) - CFRetain(font->f); - return font; -} - -uiDrawTextFont *mkTextFontFromNSFont(NSFont *f) -{ - // toll-free bridging; we do retain, though - return mkTextFont((CTFontRef) f, YES); -} - -static CFMutableDictionaryRef newAttrList(void) -{ - CFMutableDictionaryRef attr; - - attr = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (attr == NULL) - complain("error creating attribute dictionary in newAttrList()()"); - return attr; -} - -static void addFontFamilyAttr(CFMutableDictionaryRef attr, const char *family) -{ - CFStringRef cfstr; - - cfstr = CFStringCreateWithCString(NULL, family, kCFStringEncodingUTF8); - if (cfstr == NULL) - complain("error creating font family name CFStringRef in addFontFamilyAttr()"); - CFDictionaryAddValue(attr, kCTFontFamilyNameAttribute, cfstr); - CFRelease(cfstr); // dictionary holds its own reference -} - -static void addFontSizeAttr(CFMutableDictionaryRef attr, double size) -{ - CFNumberRef n; - - n = CFNumberCreate(NULL, kCFNumberDoubleType, &size); - CFDictionaryAddValue(attr, kCTFontSizeAttribute, n); - CFRelease(n); -} - -#if 0 -TODO -// See http://stackoverflow.com/questions/4810409/does-coretext-support-small-caps/4811371#4811371 and https://git.gnome.org/browse/pango/tree/pango/pangocoretext-fontmap.c for what these do -// And fortunately, unlike the traits (see below), unmatched features are simply ignored without affecting the other features :D -static void addFontSmallCapsAttr(CFMutableDictionaryRef attr) -{ - CFMutableArrayRef outerArray; - CFMutableDictionaryRef innerDict; - CFNumberRef numType, numSelector; - int num; - - outerArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - if (outerArray == NULL) - complain("error creating outer CFArray for adding small caps attributes in addFontSmallCapsAttr()"); - - // Apple's headers say these are deprecated, but a few fonts still rely on them - num = kLetterCaseType; - numType = CFNumberCreate(NULL, kCFNumberIntType, &num); - num = kSmallCapsSelector; - numSelector = CFNumberCreate(NULL, kCFNumberIntType, &num); - innerDict = newAttrList(); - CFDictionaryAddValue(innerDict, kCTFontFeatureTypeIdentifierKey, numType); - CFRelease(numType); - CFDictionaryAddValue(innerDict, kCTFontFeatureSelectorIdentifierKey, numSelector); - CFRelease(numSelector); - CFArrayAppendValue(outerArray, innerDict); - CFRelease(innerDict); // and likewise for CFArray - - // these are the non-deprecated versions of the above; some fonts have these instead - num = kLowerCaseType; - numType = CFNumberCreate(NULL, kCFNumberIntType, &num); - num = kLowerCaseSmallCapsSelector; - numSelector = CFNumberCreate(NULL, kCFNumberIntType, &num); - innerDict = newAttrList(); - CFDictionaryAddValue(innerDict, kCTFontFeatureTypeIdentifierKey, numType); - CFRelease(numType); - CFDictionaryAddValue(innerDict, kCTFontFeatureSelectorIdentifierKey, numSelector); - CFRelease(numSelector); - CFArrayAppendValue(outerArray, innerDict); - CFRelease(innerDict); // and likewise for CFArray - - CFDictionaryAddValue(attr, kCTFontFeatureSettingsAttribute, outerArray); - CFRelease(outerArray); -} -#endif - -// Named constants for these were NOT added until 10.11, and even then they were added as external symbols instead of macros, so we can't use them directly :( -// kode54 got these for me before I had access to El Capitan; thanks to him. -#define ourNSFontWeightUltraLight -0.800000 -#define ourNSFontWeightThin -0.600000 -#define ourNSFontWeightLight -0.400000 -#define ourNSFontWeightRegular 0.000000 -#define ourNSFontWeightMedium 0.230000 -#define ourNSFontWeightSemibold 0.300000 -#define ourNSFontWeightBold 0.400000 -#define ourNSFontWeightHeavy 0.560000 -#define ourNSFontWeightBlack 0.620000 -static const CGFloat ctWeights[] = { - // yeah these two have their names swapped; blame Pango - [uiDrawTextWeightThin] = ourNSFontWeightUltraLight, - [uiDrawTextWeightUltraLight] = ourNSFontWeightThin, - [uiDrawTextWeightLight] = ourNSFontWeightLight, - // for this one let's go between Light and Regular - // we're doing nearest so if there happens to be an exact value hopefully it's close enough - [uiDrawTextWeightBook] = ourNSFontWeightLight + ((ourNSFontWeightRegular - ourNSFontWeightLight) / 2), - [uiDrawTextWeightNormal] = ourNSFontWeightRegular, - [uiDrawTextWeightMedium] = ourNSFontWeightMedium, - [uiDrawTextWeightSemiBold] = ourNSFontWeightSemibold, - [uiDrawTextWeightBold] = ourNSFontWeightBold, - // for this one let's go between Bold and Heavy - [uiDrawTextWeightUltraBold] = ourNSFontWeightBold + ((ourNSFontWeightHeavy - ourNSFontWeightBold) / 2), - [uiDrawTextWeightHeavy] = ourNSFontWeightHeavy, - [uiDrawTextWeightUltraHeavy] = ourNSFontWeightBlack, -}; - -// Unfortunately there are still no named constants for these. -// Let's just use normalized widths. -// As far as I can tell (OS X only ships with condensed fonts, not expanded fonts; TODO), regardless of condensed or expanded, negative means condensed and positive means expanded. -// TODO verify this is correct -static const CGFloat ctStretches[] = { - [uiDrawTextStretchUltraCondensed] = -1.0, - [uiDrawTextStretchExtraCondensed] = -0.75, - [uiDrawTextStretchCondensed] = -0.5, - [uiDrawTextStretchSemiCondensed] = -0.25, - [uiDrawTextStretchNormal] = 0.0, - [uiDrawTextStretchSemiExpanded] = 0.25, - [uiDrawTextStretchExpanded] = 0.5, - [uiDrawTextStretchExtraExpanded] = 0.75, - [uiDrawTextStretchUltraExpanded] = 1.0, -}; - -struct closeness { - CFIndex index; - CGFloat weight; - CGFloat italic; - CGFloat stretch; - CGFloat distance; -}; - -// Stupidity: CTFont requires an **exact match for the entire traits dictionary**, otherwise it will **drop ALL the traits**. -// We have to implement the closest match ourselves. -// Also we have to do this before adding the small caps flags, because the matching descriptors won't have those. -CTFontDescriptorRef matchTraits(CTFontDescriptorRef against, uiDrawTextWeight weight, uiDrawTextItalic italic, uiDrawTextStretch stretch) -{ - CGFloat targetWeight; - CGFloat italicCloseness, obliqueCloseness, normalCloseness; - CGFloat targetStretch; - CFArrayRef matching; - CFIndex i, n; - struct closeness *closeness; - CTFontDescriptorRef current; - CTFontDescriptorRef out; - - targetWeight = ctWeights[weight]; - switch (italic) { - case uiDrawTextItalicNormal: - italicCloseness = 1; - obliqueCloseness = 1; - normalCloseness = 0; - break; - case uiDrawTextItalicOblique: - italicCloseness = 0.5; - obliqueCloseness = 0; - normalCloseness = 1; - break; - case uiDrawTextItalicItalic: - italicCloseness = 0; - obliqueCloseness = 0.5; - normalCloseness = 1; - break; - } - targetStretch = ctStretches[stretch]; - - matching = CTFontDescriptorCreateMatchingFontDescriptors(against, NULL); - if (matching == NULL) - // no matches; give the original back and hope for the best - return against; - n = CFArrayGetCount(matching); - if (n == 0) { - // likewise - CFRelease(matching); - return against; - } - - closeness = (struct closeness *) uiAlloc(n * sizeof (struct closeness), "struct closeness[]"); - for (i = 0; i < n; i++) { - CFDictionaryRef traits; - CFNumberRef cfnum; - CTFontSymbolicTraits symbolic; - - closeness[i].index = i; - - current = CFArrayGetValueAtIndex(matching, i); - traits = CTFontDescriptorCopyAttribute(current, kCTFontTraitsAttribute); - if (traits == NULL) { - // couldn't get traits; be safe by ranking it lowest - // LONGTERM figure out what the longest possible distances are - closeness[i].weight = 3; - closeness[i].italic = 2; - closeness[i].stretch = 3; - continue; - } - - symbolic = 0; // assume no symbolic traits if none are listed - cfnum = CFDictionaryGetValue(traits, kCTFontSymbolicTrait); - if (cfnum != NULL) { - SInt32 s; - - if (CFNumberGetValue(cfnum, kCFNumberSInt32Type, &s) == false) - complain("error getting symbolic traits in matchTraits()"); - symbolic = (CTFontSymbolicTraits) s; - // Get rule; do not release cfnum - } - - // now try weight - cfnum = CFDictionaryGetValue(traits, kCTFontWeightTrait); - if (cfnum != NULL) { - CGFloat val; - - // LONGTERM instead of complaining for this and width and possibly also symbolic traits above, should we just fall through to the default? - if (CFNumberGetValue(cfnum, kCFNumberCGFloatType, &val) == false) - complain("error getting weight value in matchTraits()"); - closeness[i].weight = val - targetWeight; - } else - // okay there's no weight key; let's try the literal meaning of the symbolic constant - // LONGTERM is the weight key guaranteed? - if ((symbolic & kCTFontBoldTrait) != 0) - closeness[i].weight = ourNSFontWeightBold - targetWeight; - else - closeness[i].weight = ourNSFontWeightRegular - targetWeight; - - // italics is a bit harder because Core Text doesn't expose a concept of obliqueness - // Pango just does a g_strrstr() (backwards case-sensitive search) for "Oblique" in the font's style name (see https://git.gnome.org/browse/pango/tree/pango/pangocoretext-fontmap.c); let's do that too I guess - if ((symbolic & kCTFontItalicTrait) != 0) - closeness[i].italic = italicCloseness; - else { - CFStringRef styleName; - BOOL isOblique; - - isOblique = NO; // default value - styleName = CTFontDescriptorCopyAttribute(current, kCTFontStyleNameAttribute); - if (styleName != NULL) { - CFRange range; - - // note the use of the toll-free bridge for the string literal, since CFSTR() *can* return NULL - range = CFStringFind(styleName, (CFStringRef) @"Oblique", kCFCompareBackwards); - if (range.location != kCFNotFound) - isOblique = YES; - CFRelease(styleName); - } - if (isOblique) - closeness[i].italic = obliqueCloseness; - else - closeness[i].italic = normalCloseness; - } - - // now try width - // TODO this does not seem to be enough for Skia's extended variants; the width trait is 0 but the Expanded flag is on - // TODO verify the rest of this matrix (what matrix?) - cfnum = CFDictionaryGetValue(traits, kCTFontWidthTrait); - if (cfnum != NULL) { - CGFloat val; - - if (CFNumberGetValue(cfnum, kCFNumberCGFloatType, &val) == false) - complain("error getting width value in matchTraits()"); - closeness[i].stretch = val - targetStretch; - } else - // okay there's no width key; let's try the literal meaning of the symbolic constant - // LONGTERM is the width key guaranteed? - if ((symbolic & kCTFontExpandedTrait) != 0) - closeness[i].stretch = 1.0 - targetStretch; - else if ((symbolic & kCTFontCondensedTrait) != 0) - closeness[i].stretch = -1.0 - targetStretch; - else - closeness[i].stretch = 0.0 - targetStretch; - - CFRelease(traits); - } - - // now figure out the 3-space difference between the three and sort by that - for (i = 0; i < n; i++) { - CGFloat weight, italic, stretch; - - weight = closeness[i].weight; - weight *= weight; - italic = closeness[i].italic; - italic *= italic; - stretch = closeness[i].stretch; - stretch *= stretch; - closeness[i].distance = sqrt(weight + italic + stretch); - } - qsort_b(closeness, n, sizeof (struct closeness), ^(const void *aa, const void *bb) { - const struct closeness *a = (const struct closeness *) aa; - const struct closeness *b = (const struct closeness *) bb; - - // via http://www.gnu.org/software/libc/manual/html_node/Comparison-Functions.html#Comparison-Functions - // LONGTERM is this really the best way? isn't it the same as if (*a < *b) return -1; if (*a > *b) return 1; return 0; ? - return (a->distance > b->distance) - (a->distance < b->distance); - }); - // and the first element of the sorted array is what we want - out = CFArrayGetValueAtIndex(matching, closeness[0].index); - CFRetain(out); // get rule - - // release everything - uiFree(closeness); - CFRelease(matching); - // and release the original descriptor since we no longer need it - CFRelease(against); - - return out; -} - -// Now remember what I said earlier about having to add the small caps traits after calling the above? This gets a dictionary back so we can do so. -CFMutableDictionaryRef extractAttributes(CTFontDescriptorRef desc) -{ - CFDictionaryRef dict; - CFMutableDictionaryRef mdict; - - dict = CTFontDescriptorCopyAttributes(desc); - // this might not be mutable, so make a mutable copy - mdict = CFDictionaryCreateMutableCopy(NULL, 0, dict); - CFRelease(dict); - return mdict; -} - -uiDrawTextFont *uiDrawLoadClosestFont(const uiDrawTextFontDescriptor *desc) -{ - CTFontRef f; - CFMutableDictionaryRef attr; - CTFontDescriptorRef cfdesc; - - attr = newAttrList(); - addFontFamilyAttr(attr, desc->Family); - addFontSizeAttr(attr, desc->Size); - - // now we have to do the traits matching, so create a descriptor, match the traits, and then get the attributes back - cfdesc = CTFontDescriptorCreateWithAttributes(attr); - // TODO release attr? - cfdesc = matchTraits(cfdesc, desc->Weight, desc->Italic, desc->Stretch); - - // specify the initial size again just to be safe - f = CTFontCreateWithFontDescriptor(cfdesc, desc->Size, NULL); - // TODO release cfdesc? - - return mkTextFont(f, NO); // we hold the initial reference; no need to retain again -} - -void uiDrawFreeTextFont(uiDrawTextFont *font) -{ - CFRelease(font->f); - uiFree(font); -} - -uintptr_t uiDrawTextFontHandle(uiDrawTextFont *font) -{ - return (uintptr_t) (font->f); -} - -void uiDrawTextFontDescribe(uiDrawTextFont *font, uiDrawTextFontDescriptor *desc) -{ - // TODO -} - -// text sizes and user space points are identical: -// - https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/TypoFeatures/TextSystemFeatures.html#//apple_ref/doc/uid/TP40009459-CH6-51627-BBCCHIFF text points are 72 per inch -// - https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Transforms/Transforms.html#//apple_ref/doc/uid/TP40003290-CH204-SW5 user space points are 72 per inch -void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metrics) -{ - metrics->Ascent = CTFontGetAscent(font->f); - metrics->Descent = CTFontGetDescent(font->f); - metrics->Leading = CTFontGetLeading(font->f); - metrics->UnderlinePos = CTFontGetUnderlinePosition(font->f); - metrics->UnderlineThickness = CTFontGetUnderlineThickness(font->f); -} - -struct uiDrawTextLayout { - CFMutableAttributedStringRef mas; - CFRange *charsToRanges; - double width; -}; - -uiDrawTextLayout *uiDrawNewTextLayout(const char *str, uiDrawTextFont *defaultFont, double width) -{ - uiDrawTextLayout *layout; - CFAttributedStringRef immutable; - CFMutableDictionaryRef attr; - CFStringRef backing; - CFIndex i, j, n; - - layout = uiNew(uiDrawTextLayout); - - // TODO docs say we need to use a different set of key callbacks - // TODO see if the font attribute key callbacks need to be the same - attr = newAttrList(); - // this will retain defaultFont->f; no need to worry - CFDictionaryAddValue(attr, kCTFontAttributeName, defaultFont->f); - - immutable = CFAttributedStringCreate(NULL, (CFStringRef) [NSString stringWithUTF8String:str], attr); - if (immutable == NULL) - complain("error creating immutable attributed string in uiDrawNewTextLayout()"); - CFRelease(attr); - - layout->mas = CFAttributedStringCreateMutableCopy(NULL, 0, immutable); - if (layout->mas == NULL) - complain("error creating attributed string in uiDrawNewTextLayout()"); - CFRelease(immutable); - - uiDrawTextLayoutSetWidth(layout, width); - - // unfortunately the CFRanges for attributes expect UTF-16 codepoints - // we want graphemes - // fortunately CFStringGetRangeOfComposedCharactersAtIndex() is here for us - // https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Strings/Articles/stringsClusters.html says that this does work on all multi-codepoint graphemes (despite the name), and that this is the preferred function for this particular job anyway - backing = CFAttributedStringGetString(layout->mas); - n = CFStringGetLength(backing); - // allocate one extra, just to be safe - layout->charsToRanges = (CFRange *) uiAlloc((n + 1) * sizeof (CFRange), "CFRange[]"); - i = 0; - j = 0; - while (i < n) { - CFRange range; - - range = CFStringGetRangeOfComposedCharactersAtIndex(backing, i); - i = range.location + range.length; - layout->charsToRanges[j] = range; - j++; - } - // and set the last one - layout->charsToRanges[j].location = i; - layout->charsToRanges[j].length = 0; - - return layout; -} - -void uiDrawFreeTextLayout(uiDrawTextLayout *layout) -{ - uiFree(layout->charsToRanges); - CFRelease(layout->mas); - uiFree(layout); -} - -void uiDrawTextLayoutSetWidth(uiDrawTextLayout *layout, double width) -{ - layout->width = width; -} - -struct framesetter { - CTFramesetterRef fs; - CFMutableDictionaryRef frameAttrib; - CGSize extents; -}; - -// TODO CTFrameProgression for RTL/LTR -// TODO kCTParagraphStyleSpecifierMaximumLineSpacing, kCTParagraphStyleSpecifierMinimumLineSpacing, kCTParagraphStyleSpecifierLineSpacingAdjustment for line spacing -static void mkFramesetter(uiDrawTextLayout *layout, struct framesetter *fs) -{ - CFRange fitRange; - CGFloat width; - - fs->fs = CTFramesetterCreateWithAttributedString(layout->mas); - if (fs->fs == NULL) - complain("error creating CTFramesetter object in mkFramesetter()"); - - // TODO kCTFramePathWidthAttributeName? - fs->frameAttrib = NULL; - - width = layout->width; - if (layout->width < 0) - width = CGFLOAT_MAX; - // TODO these seem to be floor()'d or truncated? - fs->extents = CTFramesetterSuggestFrameSizeWithConstraints(fs->fs, - CFRangeMake(0, 0), - fs->frameAttrib, - CGSizeMake(width, CGFLOAT_MAX), - &fitRange); // not documented as accepting NULL -} - -static void freeFramesetter(struct framesetter *fs) -{ - if (fs->frameAttrib != NULL) - CFRelease(fs->frameAttrib); - CFRelease(fs->fs); -} - -// LONGTERM allow line separation and leading to be factored into a wrapping text layout - -// TODO reconcile differences in character wrapping on platforms -void uiDrawTextLayoutExtents(uiDrawTextLayout *layout, double *width, double *height) -{ - struct framesetter fs; - - mkFramesetter(layout, &fs); - *width = fs.extents.width; - *height = fs.extents.height; - freeFramesetter(&fs); -} - -// Core Text doesn't draw onto a flipped view correctly; we have to do this -// see the iOS bits of the first example at https://developer.apple.com/library/mac/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW1 (iOS is naturally flipped) -// TODO how is this affected by the CTM? -static void prepareContextForText(CGContextRef c, CGFloat cheight, double *y) -{ - CGContextSaveGState(c); - CGContextTranslateCTM(c, 0, cheight); - CGContextScaleCTM(c, 1.0, -1.0); - CGContextSetTextMatrix(c, CGAffineTransformIdentity); - - // wait, that's not enough; we need to offset y values to account for our new flipping - *y = cheight - *y; -} - -// TODO placement is incorrect for Helvetica -void doDrawText(CGContextRef c, CGFloat cheight, double x, double y, uiDrawTextLayout *layout) -{ - struct framesetter fs; - CGRect rect; - CGPathRef path; - CTFrameRef frame; - - prepareContextForText(c, cheight, &y); - mkFramesetter(layout, &fs); - - // oh, and since we're flipped, y is the bottom-left coordinate of the rectangle, not the top-left - // since we are flipped, we subtract - y -= fs.extents.height; - - rect.origin = CGPointMake(x, y); - rect.size = fs.extents; - path = CGPathCreateWithRect(rect, NULL); - - frame = CTFramesetterCreateFrame(fs.fs, - CFRangeMake(0, 0), - path, - fs.frameAttrib); - if (frame == NULL) - complain("error creating CTFrame object in doDrawText()"); - CTFrameDraw(frame, c); - CFRelease(frame); - - CFRelease(path); - - freeFramesetter(&fs); - CGContextRestoreGState(c); -} - -// LONGTERM provide an equivalent to CTLineGetTypographicBounds() on uiDrawTextLayout? - -// LONGTERM keep this for later features and documentation purposes -#if 0 - w = CTLineGetTypographicBounds(line, &ascent, &descent, NULL); - // though CTLineGetTypographicBounds() returns 0 on error, it also returns 0 on an empty string, so we can't reasonably check for error - CFRelease(line); - - // LONGTERM provide a way to get the image bounds as a separate function later - bounds = CTLineGetImageBounds(line, c); - // though CTLineGetImageBounds() returns CGRectNull on error, it also returns CGRectNull on an empty string, so we can't reasonably check for error - - // CGContextSetTextPosition() positions at the baseline in the case of CTLineDraw(); we need the top-left corner instead - CTLineGetTypographicBounds(line, &yoff, NULL, NULL); - // remember that we're flipped, so we subtract - y -= yoff; - CGContextSetTextPosition(c, x, y); -#endif - -static CFRange charsToRange(uiDrawTextLayout *layout, int startChar, int endChar) -{ - CFRange start, end; - CFRange out; - - start = layout->charsToRanges[startChar]; - end = layout->charsToRanges[endChar]; - out.location = start.location; - out.length = end.location - start.location; - return out; -} - -#define rangeToCFRange() charsToRange(layout, startChar, endChar) - -void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endChar, double r, double g, double b, double a) -{ - CGColorSpaceRef colorspace; - CGFloat components[4]; - CGColorRef color; - - // for consistency with windows, use sRGB - colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - components[0] = r; - components[1] = g; - components[2] = b; - components[3] = a; - color = CGColorCreate(colorspace, components); - CGColorSpaceRelease(colorspace); - - CFAttributedStringSetAttribute(layout->mas, - rangeToCFRange(), - kCTForegroundColorAttributeName, - color); - CGColorRelease(color); // TODO safe? -} diff --git a/deps/libui/darwin/editablecombo.m b/deps/libui/darwin/editablecombo.m deleted file mode 100644 index 434add70f2..0000000000 --- a/deps/libui/darwin/editablecombo.m +++ /dev/null @@ -1,185 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// So why did I split uiCombobox into uiCombobox and uiEditableCombobox? Here's (90% of the; the other 10% is GTK+ events) answer: -// When you type a value into a NSComboBox that just happens to be in the list, it will autoselect that item! -// I can't seem to find a workaround. -// Fortunately, there's other weird behaviors that made this split worth it. -// And besides, selected items make little sense with editable comboboxes... you either separate or combine them with the text entry :V - -// NSComboBoxes have no intrinsic width; we'll use the default Interface Builder width for them. -#define comboboxWidth 96 - -@interface libui_intrinsicWidthNSComboBox : NSComboBox -@end - -@implementation libui_intrinsicWidthNSComboBox - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = comboboxWidth; - return s; -} - -@end - -struct uiEditableCombobox { - uiDarwinControl c; - NSComboBox *cb; - void (*onChanged)(uiEditableCombobox *, void *); - void *onChangedData; -}; - -@interface editableComboboxDelegateClass : NSObject { - struct mapTable *comboboxes; -} -- (void)controlTextDidChange:(NSNotification *)note; -- (void)comboBoxSelectionDidChange:(NSNotification *)note; -- (void)registerCombobox:(uiEditableCombobox *)c; -- (void)unregisterCombobox:(uiEditableCombobox *)c; -@end - -@implementation editableComboboxDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->comboboxes = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->comboboxes); - [super dealloc]; -} - -- (void)controlTextDidChange:(NSNotification *)note -{ - uiEditableCombobox *c; - - c = uiEditableCombobox(mapGet(self->comboboxes, [note object])); - (*(c->onChanged))(c, c->onChangedData); -} - -// the above doesn't handle when an item is selected; this will -- (void)comboBoxSelectionDidChange:(NSNotification *)note -{ - // except this is sent BEFORE the entry is changed, and that doesn't send the above, so - // this is via http://stackoverflow.com/a/21059819/3408572 - it avoids the need to manage selected items - // this still isn't perfect — I get residual changes to the same value while navigating the list — but it's good enough - [self performSelector:@selector(controlTextDidChange:) - withObject:note - afterDelay:0]; -} - -- (void)registerCombobox:(uiEditableCombobox *)c -{ - mapSet(self->comboboxes, c->cb, c); - [c->cb setDelegate:self]; -} - -- (void)unregisterCombobox:(uiEditableCombobox *)c -{ - [c->cb setDelegate:nil]; - mapDelete(self->comboboxes, c->cb); -} - -@end - -static editableComboboxDelegateClass *comboboxDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiEditableCombobox, cb) - -static void uiEditableComboboxDestroy(uiControl *cc) -{ - uiEditableCombobox *c = uiEditableCombobox(cc); - - [comboboxDelegate unregisterCombobox:c]; - [c->cb release]; - uiFreeControl(uiControl(c)); -} - -void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text) -{ - [c->cb addItemWithObjectValue:toNSString(text)]; -} - -char *uiEditableComboboxText(uiEditableCombobox *c) -{ - return uiDarwinNSStringToText([c->cb stringValue]); -} - -void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text) -{ - NSString *t; - - t = toNSString(text); - [c->cb setStringValue:t]; - // yes, let's imitate the behavior that caused uiEditableCombobox to be separate in the first place! - // just to avoid confusion when users see an option in the list in the text field but not selected in the list - [c->cb selectItemWithObjectValue:t]; -} - -#if 0 -// LONGTERM -void uiEditableComboboxSetSelected(uiEditableCombobox *c, int n) -{ - if (c->editable) { - // see https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ComboBox/Tasks/SettingComboBoxValue.html#//apple_ref/doc/uid/20000256 - id delegate; - - // this triggers the delegate; turn it off for now - delegate = [c->cb delegate]; - [c->cb setDelegate:nil]; - - // this seems to work fine for -1 too - [c->cb selectItemAtIndex:n]; - if (n == -1) - [c->cb setObjectValue:@""]; - else - [c->cb setObjectValue:[c->cb objectValueOfSelectedItem]]; - - [c->cb setDelegate:delegate]; - return; - } - [c->pb selectItemAtIndex:n]; -} -#endif - -void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data) -{ - c->onChanged = f; - c->onChangedData = data; -} - -static void defaultOnChanged(uiEditableCombobox *c, void *data) -{ - // do nothing -} - -uiEditableCombobox *uiNewEditableCombobox(void) -{ - uiEditableCombobox *c; - - uiDarwinNewControl(uiEditableCombobox, c); - - c->cb = [[libui_intrinsicWidthNSComboBox alloc] initWithFrame:NSZeroRect]; - [c->cb setUsesDataSource:NO]; - [c->cb setButtonBordered:YES]; - [c->cb setCompletes:NO]; - uiDarwinSetControlFont(c->cb, NSRegularControlSize); - - if (comboboxDelegate == nil) { - comboboxDelegate = [[editableComboboxDelegateClass new] autorelease]; - [delegates addObject:comboboxDelegate]; - } - [comboboxDelegate registerCombobox:c]; - uiEditableComboboxOnChanged(c, defaultOnChanged, NULL); - - return c; -} diff --git a/deps/libui/darwin/entry.m b/deps/libui/darwin/entry.m deleted file mode 100644 index 219d080576..0000000000 --- a/deps/libui/darwin/entry.m +++ /dev/null @@ -1,251 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// Text fields for entering text have no intrinsic width; we'll use the default Interface Builder width for them. -#define textfieldWidth 96 - -@interface libui_intrinsicWidthNSTextField : NSTextField -@end - -@implementation libui_intrinsicWidthNSTextField - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = textfieldWidth; - return s; -} - -@end - -// TODO does this have one on its own? -@interface libui_intrinsicWidthNSSecureTextField : NSSecureTextField -@end - -@implementation libui_intrinsicWidthNSSecureTextField - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = textfieldWidth; - return s; -} - -@end - -// TODO does this have one on its own? -@interface libui_intrinsicWidthNSSearchField : NSSearchField -@end - -@implementation libui_intrinsicWidthNSSearchField - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = textfieldWidth; - return s; -} - -@end - -struct uiEntry { - uiDarwinControl c; - NSTextField *textfield; - void (*onChanged)(uiEntry *, void *); - void *onChangedData; -}; - -static BOOL isSearchField(NSTextField *tf) -{ - return [tf isKindOfClass:[NSSearchField class]]; -} - -@interface entryDelegateClass : NSObject { - struct mapTable *entries; -} -- (void)controlTextDidChange:(NSNotification *)note; -- (IBAction)onSearch:(id)sender; -- (void)registerEntry:(uiEntry *)e; -- (void)unregisterEntry:(uiEntry *)e; -@end - -@implementation entryDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->entries = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->entries); - [super dealloc]; -} - -- (void)controlTextDidChange:(NSNotification *)note -{ - [self onSearch:[note object]]; -} - -- (IBAction)onSearch:(id)sender -{ - uiEntry *e; - - e = (uiEntry *) mapGet(self->entries, sender); - (*(e->onChanged))(e, e->onChangedData); -} - -- (void)registerEntry:(uiEntry *)e -{ - mapSet(self->entries, e->textfield, e); - if (isSearchField(e->textfield)) { - [e->textfield setTarget:self]; - [e->textfield setAction:@selector(onSearch:)]; - } else - [e->textfield setDelegate:self]; -} - -- (void)unregisterEntry:(uiEntry *)e -{ - if (isSearchField(e->textfield)) - [e->textfield setTarget:nil]; - else - [e->textfield setDelegate:nil]; - mapDelete(self->entries, e->textfield); -} - -@end - -static entryDelegateClass *entryDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiEntry, textfield) - -static void uiEntryDestroy(uiControl *c) -{ - uiEntry *e = uiEntry(c); - - [entryDelegate unregisterEntry:e]; - [e->textfield release]; - uiFreeControl(uiControl(e)); -} - -char *uiEntryText(uiEntry *e) -{ - return uiDarwinNSStringToText([e->textfield stringValue]); -} - -void uiEntrySetText(uiEntry *e, const char *text) -{ - [e->textfield setStringValue:toNSString(text)]; - // don't queue the control for resize; entry sizes are independent of their contents -} - -void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *, void *), void *data) -{ - e->onChanged = f; - e->onChangedData = data; -} - -int uiEntryReadOnly(uiEntry *e) -{ - return [e->textfield isEditable] == NO; -} - -void uiEntrySetReadOnly(uiEntry *e, int readonly) -{ - BOOL editable; - - editable = YES; - if (readonly) - editable = NO; - [e->textfield setEditable:editable]; -} - -static void defaultOnChanged(uiEntry *e, void *data) -{ - // do nothing -} - -// these are based on interface builder defaults; my comments in the old code weren't very good so I don't really know what talked about what, sorry :/ -void finishNewTextField(NSTextField *t, BOOL isEntry) -{ - uiDarwinSetControlFont(t, NSRegularControlSize); - - // THE ORDER OF THESE CALLS IS IMPORTANT; CHANGE IT AND THE BORDERS WILL DISAPPEAR - [t setBordered:NO]; - [t setBezelStyle:NSTextFieldSquareBezel]; - [t setBezeled:isEntry]; - - // we don't need to worry about substitutions/autocorrect here; see window_darwin.m for details - - [[t cell] setLineBreakMode:NSLineBreakByClipping]; - [[t cell] setScrollable:YES]; -} - -static NSTextField *realNewEditableTextField(Class class) -{ - NSTextField *tf; - - tf = [[class alloc] initWithFrame:NSZeroRect]; - [tf setSelectable:YES]; // otherwise the setting is masked by the editable default of YES - finishNewTextField(tf, YES); - return tf; -} - -NSTextField *newEditableTextField(void) -{ - return realNewEditableTextField([libui_intrinsicWidthNSTextField class]); -} - -static uiEntry *finishNewEntry(Class class) -{ - uiEntry *e; - - uiDarwinNewControl(uiEntry, e); - - e->textfield = realNewEditableTextField(class); - - if (entryDelegate == nil) { - entryDelegate = [[entryDelegateClass new] autorelease]; - [delegates addObject:entryDelegate]; - } - [entryDelegate registerEntry:e]; - uiEntryOnChanged(e, defaultOnChanged, NULL); - - return e; -} - -uiEntry *uiNewEntry(void) -{ - return finishNewEntry([libui_intrinsicWidthNSTextField class]); -} - -uiEntry *uiNewPasswordEntry(void) -{ - return finishNewEntry([libui_intrinsicWidthNSSecureTextField class]); -} - -uiEntry *uiNewSearchEntry(void) -{ - uiEntry *e; - NSSearchField *s; - - e = finishNewEntry([libui_intrinsicWidthNSSearchField class]); - s = (NSSearchField *) (e->textfield); - // TODO these are only on 10.10 -// [s setSendsSearchStringImmediately:NO]; -// [s setSendsWholeSearchString:NO]; - [s setBordered:NO]; - [s setBezelStyle:NSTextFieldRoundedBezel]; - [s setBezeled:YES]; - return e; -} diff --git a/deps/libui/darwin/fontbutton.m b/deps/libui/darwin/fontbutton.m deleted file mode 100644 index 22bc64659b..0000000000 --- a/deps/libui/darwin/fontbutton.m +++ /dev/null @@ -1,218 +0,0 @@ -// 14 april 2016 -#import "uipriv_darwin.h" - -@interface fontButton : NSButton { - uiFontButton *libui_b; - NSFont *libui_font; -} -- (id)initWithFrame:(NSRect)frame libuiFontButton:(uiFontButton *)b; -- (void)updateFontButtonLabel; -- (IBAction)fontButtonClicked:(id)sender; -- (void)activateFontButton; -- (void)deactivateFontButton:(BOOL)activatingAnother; -- (void)deactivateOnClose:(NSNotification *)note; -- (uiDrawTextFont *)libuiFont; -@end - -// only one may be active at one time -static fontButton *activeFontButton = nil; - -struct uiFontButton { - uiDarwinControl c; - fontButton *button; - void (*onChanged)(uiFontButton *, void *); - void *onChangedData; -}; - -@implementation fontButton - -- (id)initWithFrame:(NSRect)frame libuiFontButton:(uiFontButton *)b -{ - self = [super initWithFrame:frame]; - if (self) { - self->libui_b = b; - - // imitate a NSColorWell in appearance - [self setButtonType:NSPushOnPushOffButton]; - [self setBordered:YES]; - [self setBezelStyle:NSShadowlessSquareBezelStyle]; - - // default font values according to the CTFontDescriptor reference - // this is autoreleased (thanks swillits in irc.freenode.net/#macdev) - self->libui_font = [[NSFont fontWithName:@"Helvetica" size:12.0] retain]; - [self updateFontButtonLabel]; - - // for when clicked - [self setTarget:self]; - [self setAction:@selector(fontButtonClicked:)]; - } - return self; -} - -- (void)dealloc -{ - // clean up notifications - if (activeFontButton == self) - [self deactivateFontButton:NO]; - [self->libui_font release]; - [super dealloc]; -} - -- (void)updateFontButtonLabel -{ - NSString *title; - - title = [NSString stringWithFormat:@"%@ %g", - [self->libui_font displayName], - [self->libui_font pointSize]]; - [self setTitle:title]; -} - -- (IBAction)fontButtonClicked:(id)sender -{ - if ([self state] == NSOnState) - [self activateFontButton]; - else - [self deactivateFontButton:NO]; -} - -- (void)activateFontButton -{ - NSFontManager *sfm; - - sfm = [NSFontManager sharedFontManager]; - if (activeFontButton != nil) - [activeFontButton deactivateFontButton:YES]; - [sfm setTarget:self]; - [sfm setSelectedFont:self->libui_font isMultiple:NO]; - [sfm orderFrontFontPanel:self]; - activeFontButton = self; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(deactivateOnClose:) - name:NSWindowWillCloseNotification - object:[NSFontPanel sharedFontPanel]]; - [self setState:NSOnState]; -} - -- (void)deactivateFontButton:(BOOL)activatingAnother -{ - NSFontManager *sfm; - - sfm = [NSFontManager sharedFontManager]; - [sfm setTarget:nil]; - if (!activatingAnother) - [[NSFontPanel sharedFontPanel] orderOut:self]; - activeFontButton = nil; - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSWindowWillCloseNotification - object:[NSFontPanel sharedFontPanel]]; - [self setState:NSOffState]; -} - -- (void)deactivateOnClose:(NSNotification *)note -{ - [self deactivateFontButton:NO]; -} - -- (void)changeFont:(id)sender -{ - NSFontManager *fm; - NSFont *old; - uiFontButton *b = self->libui_b; - - fm = (NSFontManager *) sender; - old = self->libui_font; - self->libui_font = [sender convertFont:self->libui_font]; - // do this even if it returns the same; we don't own anything that isn't from a new or alloc/init - [self->libui_font retain]; - // do this second just in case - [old release]; - [self updateFontButtonLabel]; - (*(b->onChanged))(b, b->onChangedData); -} - -- (NSUInteger)validModesForFontPanel:(NSFontPanel *)panel -{ - return NSFontPanelFaceModeMask | - NSFontPanelSizeModeMask | - NSFontPanelCollectionModeMask; -} - -- (uiDrawTextFont *)libuiFont -{ - return mkTextFontFromNSFont(self->libui_font); -} - -@end - -uiDarwinControlAllDefaults(uiFontButton, button) - -// we do not want font change events to be sent to any controls other than the font buttons -// see main.m for more details -BOOL fontButtonInhibitSendAction(SEL sel, id from, id to) -{ - if (sel != @selector(changeFont:)) - return NO; - return ![to isKindOfClass:[fontButton class]]; -} - -// we do not want NSFontPanelValidation messages to be sent to any controls other than the font buttons when a font button is active -// see main.m for more details -BOOL fontButtonOverrideTargetForAction(SEL sel, id from, id to, id *override) -{ - if (activeFontButton == nil) - return NO; - if (sel != @selector(validModesForFontPanel:)) - return NO; - *override = activeFontButton; - return YES; -} - -// we also don't want the panel to be usable when there's a dialog running; see stddialogs.m for more details on that -// unfortunately the panel seems to ignore -setWorksWhenModal: so we'll have to do things ourselves -@interface nonModalFontPanel : NSFontPanel -@end - -@implementation nonModalFontPanel - -- (BOOL)worksWhenModal -{ - return NO; -} - -@end - -void setupFontPanel(void) -{ - [NSFontManager setFontPanelFactory:[nonModalFontPanel class]]; -} - -static void defaultOnChanged(uiFontButton *b, void *data) -{ - // do nothing -} - -uiDrawTextFont *uiFontButtonFont(uiFontButton *b) -{ - return [b->button libuiFont]; -} - -void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data) -{ - b->onChanged = f; - b->onChangedData = data; -} - -uiFontButton *uiNewFontButton(void) -{ - uiFontButton *b; - - uiDarwinNewControl(uiFontButton, b); - - b->button = [[fontButton alloc] initWithFrame:NSZeroRect libuiFontButton:b]; - uiDarwinSetControlFont(b->button, NSRegularControlSize); - - uiFontButtonOnChanged(b, defaultOnChanged, NULL); - - return b; -} diff --git a/deps/libui/darwin/form.m b/deps/libui/darwin/form.m deleted file mode 100644 index 7cdb965a90..0000000000 --- a/deps/libui/darwin/form.m +++ /dev/null @@ -1,561 +0,0 @@ -// 7 june 2016 -#import "uipriv_darwin.h" - -// TODO in the test program, sometimes one of the radio buttons can disappear (try when spaced) - -@interface formChild : NSView -@property uiControl *c; -@property (strong) NSTextField *label; -@property BOOL stretchy; -@property NSLayoutPriority oldHorzHuggingPri; -@property NSLayoutPriority oldVertHuggingPri; -@property (strong) NSLayoutConstraint *baseline; -@property (strong) NSLayoutConstraint *leading; -@property (strong) NSLayoutConstraint *top; -@property (strong) NSLayoutConstraint *trailing; -@property (strong) NSLayoutConstraint *bottom; -- (id)initWithLabel:(NSTextField *)l; -- (void)onDestroy; -- (NSView *)view; -@end - -@interface formView : NSView { - uiForm *f; - NSMutableArray *children; - int padded; - - NSLayoutConstraint *first; - NSMutableArray *inBetweens; - NSLayoutConstraint *last; - NSMutableArray *widths; - NSMutableArray *leadings; - NSMutableArray *middles; - NSMutableArray *trailings; -} -- (id)initWithF:(uiForm *)ff; -- (void)onDestroy; -- (void)removeOurConstraints; -- (void)syncEnableStates:(int)enabled; -- (CGFloat)paddingAmount; -- (void)establishOurConstraints; -- (void)append:(NSString *)label c:(uiControl *)c stretchy:(int)stretchy; -- (void)delete:(int)n; -- (int)isPadded; -- (void)setPadded:(int)p; -- (BOOL)hugsTrailing; -- (BOOL)hugsBottom; -- (int)nStretchy; -@end - -struct uiForm { - uiDarwinControl c; - formView *view; -}; - -@implementation formChild - -- (id)initWithLabel:(NSTextField *)l -{ - self = [super initWithFrame:NSZeroRect]; - if (self) { - self.label = l; - [self.label setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self.label setContentHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal]; - [self.label setContentHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationVertical]; - [self.label setContentCompressionResistancePriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal]; - [self.label setContentCompressionResistancePriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationVertical]; - [self addSubview:self.label]; - - self.leading = mkConstraint(self.label, NSLayoutAttributeLeading, - NSLayoutRelationGreaterThanOrEqual, - self, NSLayoutAttributeLeading, - 1, 0, - @"uiForm label leading"); - [self addConstraint:self.leading]; - self.top = mkConstraint(self.label, NSLayoutAttributeTop, - NSLayoutRelationEqual, - self, NSLayoutAttributeTop, - 1, 0, - @"uiForm label top"); - [self addConstraint:self.top]; - self.trailing = mkConstraint(self.label, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - self, NSLayoutAttributeTrailing, - 1, 0, - @"uiForm label trailing"); - [self addConstraint:self.trailing]; - self.bottom = mkConstraint(self.label, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - self, NSLayoutAttributeBottom, - 1, 0, - @"uiForm label bottom"); - [self addConstraint:self.bottom]; - } - return self; -} - -- (void)onDestroy -{ - [self removeConstraint:self.trailing]; - self.trailing = nil; - [self removeConstraint:self.top]; - self.top = nil; - [self removeConstraint:self.bottom]; - self.bottom = nil; - - [self.label removeFromSuperview]; - self.label = nil; -} - -- (NSView *)view -{ - return (NSView *) uiControlHandle(self.c); -} - -@end - -@implementation formView - -- (id)initWithF:(uiForm *)ff -{ - self = [super initWithFrame:NSZeroRect]; - if (self != nil) { - self->f = ff; - self->padded = 0; - self->children = [NSMutableArray new]; - - self->inBetweens = [NSMutableArray new]; - self->widths = [NSMutableArray new]; - self->leadings = [NSMutableArray new]; - self->middles = [NSMutableArray new]; - self->trailings = [NSMutableArray new]; - } - return self; -} - -- (void)onDestroy -{ - formChild *fc; - - [self removeOurConstraints]; - [self->inBetweens release]; - [self->widths release]; - [self->leadings release]; - [self->middles release]; - [self->trailings release]; - - for (fc in self->children) { - [self removeConstraint:fc.baseline]; - fc.baseline = nil; - uiControlSetParent(fc.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(fc.c), nil); - uiControlDestroy(fc.c); - [fc onDestroy]; - [fc removeFromSuperview]; - } - [self->children release]; -} - -- (void)removeOurConstraints -{ - if (self->first != nil) { - [self removeConstraint:self->first]; - [self->first release]; - self->first = nil; - } - if ([self->inBetweens count] != 0) { - [self removeConstraints:self->inBetweens]; - [self->inBetweens removeAllObjects]; - } - if (self->last != nil) { - [self removeConstraint:self->last]; - [self->last release]; - self->last = nil; - } - if ([self->widths count] != 0) { - [self removeConstraints:self->widths]; - [self->widths removeAllObjects]; - } - if ([self->leadings count] != 0) { - [self removeConstraints:self->leadings]; - [self->leadings removeAllObjects]; - } - if ([self->middles count] != 0) { - [self removeConstraints:self->middles]; - [self->middles removeAllObjects]; - } - if ([self->trailings count] != 0) { - [self removeConstraints:self->trailings]; - [self->trailings removeAllObjects]; - } -} - -- (void)syncEnableStates:(int)enabled -{ - formChild *fc; - - for (fc in self->children) - uiDarwinControlSyncEnableState(uiDarwinControl(fc.c), enabled); -} - -- (CGFloat)paddingAmount -{ - if (!self->padded) - return 0.0; - return uiDarwinPaddingAmount(NULL); -} - -- (void)establishOurConstraints -{ - formChild *fc; - CGFloat padding; - NSView *prev, *prevlabel; - NSLayoutConstraint *c; - - [self removeOurConstraints]; - if ([self->children count] == 0) - return; - padding = [self paddingAmount]; - - // first arrange the children vertically and make them the same width - prev = nil; - for (fc in self->children) { - [fc setHidden:!uiControlVisible(fc.c)]; - if (!uiControlVisible(fc.c)) - continue; - if (prev == nil) { // first view - self->first = mkConstraint(self, NSLayoutAttributeTop, - NSLayoutRelationEqual, - [fc view], NSLayoutAttributeTop, - 1, 0, - @"uiForm first vertical constraint"); - [self addConstraint:self->first]; - [self->first retain]; - prev = [fc view]; - prevlabel = fc; - continue; - } - // not the first; link it - c = mkConstraint(prev, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - [fc view], NSLayoutAttributeTop, - 1, -padding, - @"uiForm in-between vertical constraint"); - [self addConstraint:c]; - [self->inBetweens addObject:c]; - // and make the same width - c = mkConstraint(prev, NSLayoutAttributeWidth, - NSLayoutRelationEqual, - [fc view], NSLayoutAttributeWidth, - 1, 0, - @"uiForm control width constraint"); - [self addConstraint:c]; - [self->widths addObject:c]; - c = mkConstraint(prevlabel, NSLayoutAttributeWidth, - NSLayoutRelationEqual, - fc, NSLayoutAttributeWidth, - 1, 0, - @"uiForm label lwidth constraint"); - [self addConstraint:c]; - [self->widths addObject:c]; - prev = [fc view]; - prevlabel = fc; - } - if (prev == nil) // all hidden; act as if nothing there - return; - self->last = mkConstraint(prev, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - self, NSLayoutAttributeBottom, - 1, 0, - @"uiForm last vertical constraint"); - [self addConstraint:self->last]; - [self->last retain]; - - // now arrange the controls horizontally - for (fc in self->children) { - if (!uiControlVisible(fc.c)) - continue; - c = mkConstraint(self, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - fc, NSLayoutAttributeLeading, - 1, 0, - @"uiForm leading constraint"); - [self addConstraint:c]; - [self->leadings addObject:c]; - // coerce the control to be as wide as possible - // see http://stackoverflow.com/questions/37710892/in-auto-layout-i-set-up-labels-that-shouldnt-grow-horizontally-and-controls-th - c = mkConstraint(self, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - [fc view], NSLayoutAttributeLeading, - 1, 0, - @"uiForm leading constraint"); - [c setPriority:NSLayoutPriorityDefaultHigh]; - [self addConstraint:c]; - [self->leadings addObject:c]; - c = mkConstraint(fc, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - [fc view], NSLayoutAttributeLeading, - 1, -padding, - @"uiForm middle constraint"); - [self addConstraint:c]; - [self->middles addObject:c]; - c = mkConstraint([fc view], NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - self, NSLayoutAttributeTrailing, - 1, 0, - @"uiForm trailing constraint"); - [self addConstraint:c]; - [self->trailings addObject:c]; - // TODO - c = mkConstraint(fc, NSLayoutAttributeBottom, - NSLayoutRelationLessThanOrEqual, - self, NSLayoutAttributeBottom, - 1, 0, - @"TODO"); - [self addConstraint:c]; - [self->trailings addObject:c]; - } - - // and make all stretchy controls have the same height - prev = nil; - for (fc in self->children) { - if (!uiControlVisible(fc.c)) - continue; - if (!fc.stretchy) - continue; - if (prev == nil) { - prev = [fc view]; - continue; - } - c = mkConstraint([fc view], NSLayoutAttributeHeight, - NSLayoutRelationEqual, - prev, NSLayoutAttributeHeight, - 1, 0, - @"uiForm stretchy constraint"); - [self addConstraint:c]; - // TODO make a dedicated array for this - [self->leadings addObject:c]; - } - - // we don't arrange the labels vertically; that's done when we add the control since those constraints don't need to change (they just need to be at their baseline) -} - -- (void)append:(NSString *)label c:(uiControl *)c stretchy:(int)stretchy -{ - formChild *fc; - NSLayoutPriority priority; - NSLayoutAttribute attribute; - int oldnStretchy; - - fc = [[formChild alloc] initWithLabel:newLabel(label)]; - fc.c = c; - fc.stretchy = stretchy; - fc.oldHorzHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(fc.c), NSLayoutConstraintOrientationHorizontal); - fc.oldVertHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(fc.c), NSLayoutConstraintOrientationVertical); - [fc setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self addSubview:fc]; - - uiControlSetParent(fc.c, uiControl(self->f)); - uiDarwinControlSetSuperview(uiDarwinControl(fc.c), self); - uiDarwinControlSyncEnableState(uiDarwinControl(fc.c), uiControlEnabledToUser(uiControl(self->f))); - - // if a control is stretchy, it should not hug vertically - // otherwise, it should *forcibly* hug - if (fc.stretchy) - priority = NSLayoutPriorityDefaultLow; - else - // LONGTERM will default high work? - priority = NSLayoutPriorityRequired; - uiDarwinControlSetHuggingPriority(uiDarwinControl(fc.c), priority, NSLayoutConstraintOrientationVertical); - // make sure controls don't hug their horizontal direction so they fill the width of the view - uiDarwinControlSetHuggingPriority(uiDarwinControl(fc.c), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationHorizontal); - - // and constrain the baselines to position the label vertically - // if the view is a scroll view, align tops, not baselines - // this is what Interface Builder does - attribute = NSLayoutAttributeBaseline; - if ([[fc view] isKindOfClass:[NSScrollView class]]) - attribute = NSLayoutAttributeTop; - fc.baseline = mkConstraint(fc.label, attribute, - NSLayoutRelationEqual, - [fc view], attribute, - 1, 0, - @"uiForm baseline constraint"); - [self addConstraint:fc.baseline]; - - oldnStretchy = [self nStretchy]; - [self->children addObject:fc]; - - [self establishOurConstraints]; - if (fc.stretchy) - if (oldnStretchy == 0) - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(self->f)); - - [fc release]; // we don't need the initial reference now -} - -- (void)delete:(int)n -{ - formChild *fc; - int stretchy; - - fc = (formChild *) [self->children objectAtIndex:n]; - stretchy = fc.stretchy; - - uiControlSetParent(fc.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(fc.c), nil); - - uiDarwinControlSetHuggingPriority(uiDarwinControl(fc.c), fc.oldHorzHuggingPri, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(fc.c), fc.oldVertHuggingPri, NSLayoutConstraintOrientationVertical); - - [fc onDestroy]; - [self->children removeObjectAtIndex:n]; - - [self establishOurConstraints]; - if (stretchy) - if ([self nStretchy] == 0) - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(self->f)); -} - -- (int)isPadded -{ - return self->padded; -} - -- (void)setPadded:(int)p -{ - CGFloat padding; - NSLayoutConstraint *c; - - self->padded = p; - padding = [self paddingAmount]; - for (c in self->inBetweens) - [c setConstant:-padding]; - for (c in self->middles) - [c setConstant:-padding]; -} - -- (BOOL)hugsTrailing -{ - return YES; // always hug trailing -} - -- (BOOL)hugsBottom -{ - // only hug if we have stretchy - return [self nStretchy] != 0; -} - -- (int)nStretchy -{ - formChild *fc; - int n; - - n = 0; - for (fc in self->children) { - if (!uiControlVisible(fc.c)) - continue; - if (fc.stretchy) - n++; - } - return n; -} - -@end - -static void uiFormDestroy(uiControl *c) -{ - uiForm *f = uiForm(c); - - [f->view onDestroy]; - [f->view release]; - uiFreeControl(uiControl(f)); -} - -uiDarwinControlDefaultHandle(uiForm, view) -uiDarwinControlDefaultParent(uiForm, view) -uiDarwinControlDefaultSetParent(uiForm, view) -uiDarwinControlDefaultToplevel(uiForm, view) -uiDarwinControlDefaultVisible(uiForm, view) -uiDarwinControlDefaultShow(uiForm, view) -uiDarwinControlDefaultHide(uiForm, view) -uiDarwinControlDefaultEnabled(uiForm, view) -uiDarwinControlDefaultEnable(uiForm, view) -uiDarwinControlDefaultDisable(uiForm, view) - -static void uiFormSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiForm *f = uiForm(c); - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(f), enabled)) - return; - [f->view syncEnableStates:enabled]; -} - -uiDarwinControlDefaultSetSuperview(uiForm, view) - -static BOOL uiFormHugsTrailingEdge(uiDarwinControl *c) -{ - uiForm *f = uiForm(c); - - return [f->view hugsTrailing]; -} - -static BOOL uiFormHugsBottom(uiDarwinControl *c) -{ - uiForm *f = uiForm(c); - - return [f->view hugsBottom]; -} - -static void uiFormChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiForm *f = uiForm(c); - - [f->view establishOurConstraints]; -} - -uiDarwinControlDefaultHuggingPriority(uiForm, view) -uiDarwinControlDefaultSetHuggingPriority(uiForm, view) - -static void uiFormChildVisibilityChanged(uiDarwinControl *c) -{ - uiForm *f = uiForm(c); - - [f->view establishOurConstraints]; -} - -void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy) -{ - // LONGTERM on other platforms - // or at leat allow this and implicitly turn it into a spacer - if (c == NULL) - userbug("You cannot add NULL to a uiForm."); - [f->view append:toNSString(label) c:c stretchy:stretchy]; -} - -void uiFormDelete(uiForm *f, int n) -{ - [f->view delete:n]; -} - -int uiFormPadded(uiForm *f) -{ - return [f->view isPadded]; -} - -void uiFormSetPadded(uiForm *f, int padded) -{ - [f->view setPadded:padded]; -} - -uiForm *uiNewForm(void) -{ - uiForm *f; - - uiDarwinNewControl(uiForm, f); - - f->view = [[formView alloc] initWithF:f]; - - return f; -} diff --git a/deps/libui/darwin/grid.m b/deps/libui/darwin/grid.m deleted file mode 100644 index d5c5fb1e86..0000000000 --- a/deps/libui/darwin/grid.m +++ /dev/null @@ -1,800 +0,0 @@ -// 11 june 2016 -#import "uipriv_darwin.h" - -// TODO the assorted test doesn't work right at all - -@interface gridChild : NSView -@property uiControl *c; -@property int left; -@property int top; -@property int xspan; -@property int yspan; -@property int hexpand; -@property uiAlign halign; -@property int vexpand; -@property uiAlign valign; - -@property (strong) NSLayoutConstraint *leadingc; -@property (strong) NSLayoutConstraint *topc; -@property (strong) NSLayoutConstraint *trailingc; -@property (strong) NSLayoutConstraint *bottomc; -@property (strong) NSLayoutConstraint *xcenterc; -@property (strong) NSLayoutConstraint *ycenterc; - -@property NSLayoutPriority oldHorzHuggingPri; -@property NSLayoutPriority oldVertHuggingPri; -- (void)setC:(uiControl *)c grid:(uiGrid *)g; -- (void)onDestroy; -- (NSView *)view; -@end - -@interface gridView : NSView { - uiGrid *g; - NSMutableArray *children; - int padded; - - NSMutableArray *edges; - NSMutableArray *inBetweens; - - NSMutableArray *emptyCellViews; -} -- (id)initWithG:(uiGrid *)gg; -- (void)onDestroy; -- (void)removeOurConstraints; -- (void)syncEnableStates:(int)enabled; -- (CGFloat)paddingAmount; -- (void)establishOurConstraints; -- (void)append:(gridChild *)gc; -- (void)insert:(gridChild *)gc after:(uiControl *)c at:(uiAt)at; -- (int)isPadded; -- (void)setPadded:(int)p; -- (BOOL)hugsTrailing; -- (BOOL)hugsBottom; -- (int)nhexpand; -- (int)nvexpand; -@end - -struct uiGrid { - uiDarwinControl c; - gridView *view; -}; - -@implementation gridChild - -- (void)setC:(uiControl *)c grid:(uiGrid *)g -{ - self.c = c; - self.oldHorzHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(self.c), NSLayoutConstraintOrientationHorizontal); - self.oldVertHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(self.c), NSLayoutConstraintOrientationVertical); - - uiControlSetParent(self.c, uiControl(g)); - uiDarwinControlSetSuperview(uiDarwinControl(self.c), self); - uiDarwinControlSyncEnableState(uiDarwinControl(self.c), uiControlEnabledToUser(uiControl(g))); - - if (self.halign == uiAlignStart || self.halign == uiAlignFill) { - self.leadingc = mkConstraint(self, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeLeading, - 1, 0, - @"uiGrid child horizontal alignment start constraint"); - [self addConstraint:self.leadingc]; - } - if (self.halign == uiAlignCenter) { - self.xcenterc = mkConstraint(self, NSLayoutAttributeCenterX, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeCenterX, - 1, 0, - @"uiGrid child horizontal alignment center constraint"); - [self addConstraint:self.xcenterc]; - } - if (self.halign == uiAlignEnd || self.halign == uiAlignFill) { - self.trailingc = mkConstraint(self, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeTrailing, - 1, 0, - @"uiGrid child horizontal alignment end constraint"); - [self addConstraint:self.trailingc]; - } - - if (self.valign == uiAlignStart || self.valign == uiAlignFill) { - self.topc = mkConstraint(self, NSLayoutAttributeTop, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeTop, - 1, 0, - @"uiGrid child vertical alignment start constraint"); - [self addConstraint:self.topc]; - } - if (self.valign == uiAlignCenter) { - self.ycenterc = mkConstraint(self, NSLayoutAttributeCenterY, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeCenterY, - 1, 0, - @"uiGrid child vertical alignment center constraint"); - [self addConstraint:self.ycenterc]; - } - if (self.valign == uiAlignEnd || self.valign == uiAlignFill) { - self.bottomc = mkConstraint(self, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeBottom, - 1, 0, - @"uiGrid child vertical alignment end constraint"); - [self addConstraint:self.bottomc]; - } -} - -- (void)onDestroy -{ - if (self.leadingc != nil) { - [self removeConstraint:self.leadingc]; - self.leadingc = nil; - } - if (self.topc != nil) { - [self removeConstraint:self.topc]; - self.topc = nil; - } - if (self.trailingc != nil) { - [self removeConstraint:self.trailingc]; - self.trailingc = nil; - } - if (self.bottomc != nil) { - [self removeConstraint:self.bottomc]; - self.bottomc = nil; - } - if (self.xcenterc != nil) { - [self removeConstraint:self.xcenterc]; - self.xcenterc = nil; - } - if (self.ycenterc != nil) { - [self removeConstraint:self.ycenterc]; - self.ycenterc = nil; - } - - uiControlSetParent(self.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(self.c), nil); - uiDarwinControlSetHuggingPriority(uiDarwinControl(self.c), self.oldHorzHuggingPri, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(self.c), self.oldVertHuggingPri, NSLayoutConstraintOrientationVertical); -} - -- (NSView *)view -{ - return (NSView *) uiControlHandle(self.c); -} - -@end - -@implementation gridView - -- (id)initWithG:(uiGrid *)gg -{ - self = [super initWithFrame:NSZeroRect]; - if (self != nil) { - self->g = gg; - self->padded = 0; - self->children = [NSMutableArray new]; - - self->edges = [NSMutableArray new]; - self->inBetweens = [NSMutableArray new]; - - self->emptyCellViews = [NSMutableArray new]; - } - return self; -} - -- (void)onDestroy -{ - gridChild *gc; - - [self removeOurConstraints]; - [self->edges release]; - [self->inBetweens release]; - - [self->emptyCellViews release]; - - for (gc in self->children) { - [gc onDestroy]; - uiControlDestroy(gc.c); - [gc removeFromSuperview]; - } - [self->children release]; -} - -- (void)removeOurConstraints -{ - NSView *v; - - if ([self->edges count] != 0) { - [self removeConstraints:self->edges]; - [self->edges removeAllObjects]; - } - if ([self->inBetweens count] != 0) { - [self removeConstraints:self->inBetweens]; - [self->inBetweens removeAllObjects]; - } - - for (v in self->emptyCellViews) - [v removeFromSuperview]; - [self->emptyCellViews removeAllObjects]; -} - -- (void)syncEnableStates:(int)enabled -{ - gridChild *gc; - - for (gc in self->children) - uiDarwinControlSyncEnableState(uiDarwinControl(gc.c), enabled); -} - -- (CGFloat)paddingAmount -{ - if (!self->padded) - return 0.0; - return uiDarwinPaddingAmount(NULL); -} - -// LONGTERM stop early if all controls are hidden -- (void)establishOurConstraints -{ - gridChild *gc; - CGFloat padding; - int xmin, ymin; - int xmax, ymax; - int xcount, ycount; - BOOL first; - int **gg; - NSView ***gv; - BOOL **gspan; - int x, y; - int i; - NSLayoutConstraint *c; - int firstx, firsty; - BOOL *hexpand, *vexpand; - BOOL doit; - BOOL onlyEmptyAndSpanning; - - [self removeOurConstraints]; - if ([self->children count] == 0) - return; - padding = [self paddingAmount]; - - // first, figure out the minimum and maximum row and column numbers - // ignore hidden controls - first = YES; - for (gc in self->children) { - // this bit is important: it ensures row ymin and column xmin have at least one cell to draw, so the onlyEmptyAndSpanning logic below will never run on those rows - if (!uiControlVisible(gc.c)) - continue; - if (first) { - xmin = gc.left; - ymin = gc.top; - xmax = gc.left + gc.xspan; - ymax = gc.top + gc.yspan; - first = NO; - continue; - } - if (xmin > gc.left) - xmin = gc.left; - if (ymin > gc.top) - ymin = gc.top; - if (xmax < (gc.left + gc.xspan)) - xmax = gc.left + gc.xspan; - if (ymax < (gc.top + gc.yspan)) - ymax = gc.top + gc.yspan; - } - if (first != NO) // the entire grid is hidden; do nothing - return; - xcount = xmax - xmin; - ycount = ymax - ymin; - - // now build a topological map of the grid gg[y][x] - // also figure out which cells contain spanned views so they can be ignored later - // treat hidden controls by keeping the indices -1 - gg = (int **) uiAlloc(ycount * sizeof (int *), "int[][]"); - gspan = (BOOL **) uiAlloc(ycount * sizeof (BOOL *), "BOOL[][]"); - for (y = 0; y < ycount; y++) { - gg[y] = (int *) uiAlloc(xcount * sizeof (int), "int[]"); - gspan[y] = (BOOL *) uiAlloc(xcount * sizeof (BOOL), "BOOL[]"); - for (x = 0; x < xcount; x++) - gg[y][x] = -1; // empty - } - for (i = 0; i < [self->children count]; i++) { - gc = (gridChild *) [self->children objectAtIndex:i]; - if (!uiControlVisible(gc.c)) - continue; - for (y = gc.top; y < gc.top + gc.yspan; y++) - for (x = gc.left; x < gc.left + gc.xspan; x++) { - gg[y - ymin][x - xmin] = i; - if (x != gc.left || y != gc.top) - gspan[y - ymin][x - xmin] = YES; - } - } - - // if a row or column only contains emptys and spanning cells of a opposite-direction spannings, remove it by duplicating the previous row or column - for (y = 0; y < ycount; y++) { - onlyEmptyAndSpanning = YES; - for (x = 0; x < xcount; x++) - if (gg[y][x] != -1) { - gc = (gridChild *) [self->children objectAtIndex:gg[y][x]]; - if (gc.yspan == 1 || gc.top - ymin == y) { - onlyEmptyAndSpanning = NO; - break; - } - } - if (onlyEmptyAndSpanning) - for (x = 0; x < xcount; x++) { - gg[y][x] = gg[y - 1][x]; - gspan[y][x] = YES; - } - } - for (x = 0; x < xcount; x++) { - onlyEmptyAndSpanning = YES; - for (y = 0; y < ycount; y++) - if (gg[y][x] != -1) { - gc = (gridChild *) [self->children objectAtIndex:gg[y][x]]; - if (gc.xspan == 1 || gc.left - xmin == x) { - onlyEmptyAndSpanning = NO; - break; - } - } - if (onlyEmptyAndSpanning) - for (y = 0; y < ycount; y++) { - gg[y][x] = gg[y][x - 1]; - gspan[y][x] = YES; - } - } - - // now build a topological map of the grid's views gv[y][x] - // for any empty cell, create a dummy view - gv = (NSView ***) uiAlloc(ycount * sizeof (NSView **), "NSView *[][]"); - for (y = 0; y < ycount; y++) { - gv[y] = (NSView **) uiAlloc(xcount * sizeof (NSView *), "NSView *[]"); - for (x = 0; x < xcount; x++) - if (gg[y][x] == -1) { - gv[y][x] = [[NSView alloc] initWithFrame:NSZeroRect]; - [gv[y][x] setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self addSubview:gv[y][x]]; - [self->emptyCellViews addObject:gv[y][x]]; - } else { - gc = (gridChild *) [self->children objectAtIndex:gg[y][x]]; - gv[y][x] = gc; - } - } - - // now figure out which rows and columns really expand - hexpand = (BOOL *) uiAlloc(xcount * sizeof (BOOL), "BOOL[]"); - vexpand = (BOOL *) uiAlloc(ycount * sizeof (BOOL), "BOOL[]"); - // first, which don't span - for (gc in self->children) { - if (!uiControlVisible(gc.c)) - continue; - if (gc.hexpand && gc.xspan == 1) - hexpand[gc.left - xmin] = YES; - if (gc.vexpand && gc.yspan == 1) - vexpand[gc.top - ymin] = YES; - } - // second, which do span - // the way we handle this is simple: if none of the spanned rows/columns expand, make all rows/columns expand - for (gc in self->children) { - if (!uiControlVisible(gc.c)) - continue; - if (gc.hexpand && gc.xspan != 1) { - doit = YES; - for (x = gc.left; x < gc.left + gc.xspan; x++) - if (hexpand[x - xmin]) { - doit = NO; - break; - } - if (doit) - for (x = gc.left; x < gc.left + gc.xspan; x++) - hexpand[x - xmin] = YES; - } - if (gc.vexpand && gc.yspan != 1) { - doit = YES; - for (y = gc.top; y < gc.top + gc.yspan; y++) - if (vexpand[y - ymin]) { - doit = NO; - break; - } - if (doit) - for (y = gc.top; y < gc.top + gc.yspan; y++) - vexpand[y - ymin] = YES; - } - } - - // now establish all the edge constraints - // leading and trailing edges - for (y = 0; y < ycount; y++) { - c = mkConstraint(self, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - gv[y][0], NSLayoutAttributeLeading, - 1, 0, - @"uiGrid leading edge constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - c = mkConstraint(self, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - gv[y][xcount - 1], NSLayoutAttributeTrailing, - 1, 0, - @"uiGrid trailing edge constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - } - // top and bottom edges - for (x = 0; x < xcount; x++) { - c = mkConstraint(self, NSLayoutAttributeTop, - NSLayoutRelationEqual, - gv[0][x], NSLayoutAttributeTop, - 1, 0, - @"uiGrid top edge constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - c = mkConstraint(self, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - gv[ycount - 1][x], NSLayoutAttributeBottom, - 1, 0, - @"uiGrid bottom edge constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - } - - // now align leading and top edges - // do NOT align spanning cells! - for (x = 0; x < xcount; x++) { - for (y = 0; y < ycount; y++) - if (!gspan[y][x]) - break; - firsty = y; - for (y++; y < ycount; y++) { - if (gspan[y][x]) - continue; - c = mkConstraint(gv[firsty][x], NSLayoutAttributeLeading, - NSLayoutRelationEqual, - gv[y][x], NSLayoutAttributeLeading, - 1, 0, - @"uiGrid column leading constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - } - } - for (y = 0; y < ycount; y++) { - for (x = 0; x < xcount; x++) - if (!gspan[y][x]) - break; - firstx = x; - for (x++; x < xcount; x++) { - if (gspan[y][x]) - continue; - c = mkConstraint(gv[y][firstx], NSLayoutAttributeTop, - NSLayoutRelationEqual, - gv[y][x], NSLayoutAttributeTop, - 1, 0, - @"uiGrid row top constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - } - } - - // now string adjacent views together - for (y = 0; y < ycount; y++) - for (x = 1; x < xcount; x++) - if (gv[y][x - 1] != gv[y][x]) { - c = mkConstraint(gv[y][x - 1], NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - gv[y][x], NSLayoutAttributeLeading, - 1, -padding, - @"uiGrid internal horizontal constraint"); - [self addConstraint:c]; - [self->inBetweens addObject:c]; - } - for (x = 0; x < xcount; x++) - for (y = 1; y < ycount; y++) - if (gv[y - 1][x] != gv[y][x]) { - c = mkConstraint(gv[y - 1][x], NSLayoutAttributeBottom, - NSLayoutRelationEqual, - gv[y][x], NSLayoutAttributeTop, - 1, -padding, - @"uiGrid internal vertical constraint"); - [self addConstraint:c]; - [self->inBetweens addObject:c]; - } - - // now set priorities for all widgets that expand or not - // if a cell is in an expanding row, OR If it spans, then it must be willing to stretch - // otherwise, it tries not to - // note we don't use NSLayoutPriorityRequired as that will cause things to squish when they shouldn't - for (gc in self->children) { - NSLayoutPriority priority; - - if (!uiControlVisible(gc.c)) - continue; - if (hexpand[gc.left - xmin] || gc.xspan != 1) - priority = NSLayoutPriorityDefaultLow; - else - priority = NSLayoutPriorityDefaultHigh; - uiDarwinControlSetHuggingPriority(uiDarwinControl(gc.c), priority, NSLayoutConstraintOrientationHorizontal); - // same for vertical direction - if (vexpand[gc.top - ymin] || gc.yspan != 1) - priority = NSLayoutPriorityDefaultLow; - else - priority = NSLayoutPriorityDefaultHigh; - uiDarwinControlSetHuggingPriority(uiDarwinControl(gc.c), priority, NSLayoutConstraintOrientationVertical); - } - - // TODO make all expanding rows/columns the same height/width - - // and finally clean up - uiFree(hexpand); - uiFree(vexpand); - for (y = 0; y < ycount; y++) { - uiFree(gg[y]); - uiFree(gv[y]); - uiFree(gspan[y]); - } - uiFree(gg); - uiFree(gv); - uiFree(gspan); -} - -- (void)append:(gridChild *)gc -{ - BOOL update; - int oldnh, oldnv; - - [gc setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self addSubview:gc]; - - // no need to set priority here; that's done in establishOurConstraints - - oldnh = [self nhexpand]; - oldnv = [self nvexpand]; - [self->children addObject:gc]; - - [self establishOurConstraints]; - update = NO; - if (gc.hexpand) - if (oldnh == 0) - update = YES; - if (gc.vexpand) - if (oldnv == 0) - update = YES; - if (update) - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(self->g)); - - [gc release]; // we don't need the initial reference now -} - -- (void)insert:(gridChild *)gc after:(uiControl *)c at:(uiAt)at -{ - gridChild *other; - BOOL found; - - found = NO; - for (other in self->children) - if (other.c == c) { - found = YES; - break; - } - if (!found) - userbug("Existing control %p is not in grid %p; you cannot add other controls next to it", c, self->g); - - switch (at) { - case uiAtLeading: - gc.left = other.left - gc.xspan; - gc.top = other.top; - break; - case uiAtTop: - gc.left = other.left; - gc.top = other.top - gc.yspan; - break; - case uiAtTrailing: - gc.left = other.left + other.xspan; - gc.top = other.top; - break; - case uiAtBottom: - gc.left = other.left; - gc.top = other.top + other.yspan; - break; - // TODO add error checks to ALL enums - } - - [self append:gc]; -} - -- (int)isPadded -{ - return self->padded; -} - -- (void)setPadded:(int)p -{ - CGFloat padding; - NSLayoutConstraint *c; - -#if 0 /* TODO */ -dispatch_after( -dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), -dispatch_get_main_queue(), -^{ [[self window] visualizeConstraints:[self constraints]]; } -); -#endif - self->padded = p; - padding = [self paddingAmount]; - for (c in self->inBetweens) - switch ([c firstAttribute]) { - case NSLayoutAttributeLeading: - case NSLayoutAttributeTop: - [c setConstant:padding]; - break; - case NSLayoutAttributeTrailing: - case NSLayoutAttributeBottom: - [c setConstant:-padding]; - break; - } -} - -- (BOOL)hugsTrailing -{ - // only hug if we have horizontally expanding - return [self nhexpand] != 0; -} - -- (BOOL)hugsBottom -{ - // only hug if we have vertically expanding - return [self nvexpand] != 0; -} - -- (int)nhexpand -{ - gridChild *gc; - int n; - - n = 0; - for (gc in self->children) { - if (!uiControlVisible(gc.c)) - continue; - if (gc.hexpand) - n++; - } - return n; -} - -- (int)nvexpand -{ - gridChild *gc; - int n; - - n = 0; - for (gc in self->children) { - if (!uiControlVisible(gc.c)) - continue; - if (gc.vexpand) - n++; - } - return n; -} - -@end - -static void uiGridDestroy(uiControl *c) -{ - uiGrid *g = uiGrid(c); - - [g->view onDestroy]; - [g->view release]; - uiFreeControl(uiControl(g)); -} - -uiDarwinControlDefaultHandle(uiGrid, view) -uiDarwinControlDefaultParent(uiGrid, view) -uiDarwinControlDefaultSetParent(uiGrid, view) -uiDarwinControlDefaultToplevel(uiGrid, view) -uiDarwinControlDefaultVisible(uiGrid, view) -uiDarwinControlDefaultShow(uiGrid, view) -uiDarwinControlDefaultHide(uiGrid, view) -uiDarwinControlDefaultEnabled(uiGrid, view) -uiDarwinControlDefaultEnable(uiGrid, view) -uiDarwinControlDefaultDisable(uiGrid, view) - -static void uiGridSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiGrid *g = uiGrid(c); - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(g), enabled)) - return; - [g->view syncEnableStates:enabled]; -} - -uiDarwinControlDefaultSetSuperview(uiGrid, view) - -static BOOL uiGridHugsTrailingEdge(uiDarwinControl *c) -{ - uiGrid *g = uiGrid(c); - - return [g->view hugsTrailing]; -} - -static BOOL uiGridHugsBottom(uiDarwinControl *c) -{ - uiGrid *g = uiGrid(c); - - return [g->view hugsBottom]; -} - -static void uiGridChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiGrid *g = uiGrid(c); - - [g->view establishOurConstraints]; -} - -uiDarwinControlDefaultHuggingPriority(uiGrid, view) -uiDarwinControlDefaultSetHuggingPriority(uiGrid, view) - -static void uiGridChildVisibilityChanged(uiDarwinControl *c) -{ - uiGrid *g = uiGrid(c); - - [g->view establishOurConstraints]; -} - -static gridChild *toChild(uiControl *c, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign, uiGrid *g) -{ - gridChild *gc; - - if (xspan < 0) - userbug("You cannot have a negative xspan in a uiGrid cell."); - if (yspan < 0) - userbug("You cannot have a negative yspan in a uiGrid cell."); - gc = [gridChild new]; - gc.xspan = xspan; - gc.yspan = yspan; - gc.hexpand = hexpand; - gc.halign = halign; - gc.vexpand = vexpand; - gc.valign = valign; - [gc setC:c grid:g]; - return gc; -} - -void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - gridChild *gc; - - // LONGTERM on other platforms - // or at leat allow this and implicitly turn it into a spacer - if (c == NULL) - userbug("You cannot add NULL to a uiGrid."); - gc = toChild(c, xspan, yspan, hexpand, halign, vexpand, valign, g); - gc.left = left; - gc.top = top; - [g->view append:gc]; -} - -void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - gridChild *gc; - - gc = toChild(c, xspan, yspan, hexpand, halign, vexpand, valign, g); - [g->view insert:gc after:existing at:at]; -} - -int uiGridPadded(uiGrid *g) -{ - return [g->view isPadded]; -} - -void uiGridSetPadded(uiGrid *g, int padded) -{ - [g->view setPadded:padded]; -} - -uiGrid *uiNewGrid(void) -{ - uiGrid *g; - - uiDarwinNewControl(uiGrid, g); - - g->view = [[gridView alloc] initWithG:g]; - - return g; -} diff --git a/deps/libui/darwin/group.m b/deps/libui/darwin/group.m deleted file mode 100644 index 0050bbdd3c..0000000000 --- a/deps/libui/darwin/group.m +++ /dev/null @@ -1,194 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -struct uiGroup { - uiDarwinControl c; - NSBox *box; - uiControl *child; - NSLayoutPriority oldHorzHuggingPri; - NSLayoutPriority oldVertHuggingPri; - int margined; - struct singleChildConstraints constraints; - NSLayoutPriority horzHuggingPri; - NSLayoutPriority vertHuggingPri; -}; - -static void removeConstraints(uiGroup *g) -{ - // set to contentView instead of to the box itself, otherwise we get clipping underneath the label - singleChildConstraintsRemove(&(g->constraints), [g->box contentView]); -} - -static void uiGroupDestroy(uiControl *c) -{ - uiGroup *g = uiGroup(c); - - removeConstraints(g); - if (g->child != NULL) { - uiControlSetParent(g->child, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(g->child), nil); - uiControlDestroy(g->child); - } - [g->box release]; - uiFreeControl(uiControl(g)); -} - -uiDarwinControlDefaultHandle(uiGroup, box) -uiDarwinControlDefaultParent(uiGroup, box) -uiDarwinControlDefaultSetParent(uiGroup, box) -uiDarwinControlDefaultToplevel(uiGroup, box) -uiDarwinControlDefaultVisible(uiGroup, box) -uiDarwinControlDefaultShow(uiGroup, box) -uiDarwinControlDefaultHide(uiGroup, box) -uiDarwinControlDefaultEnabled(uiGroup, box) -uiDarwinControlDefaultEnable(uiGroup, box) -uiDarwinControlDefaultDisable(uiGroup, box) - -static void uiGroupSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiGroup *g = uiGroup(c); - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(g), enabled)) - return; - if (g->child != NULL) - uiDarwinControlSyncEnableState(uiDarwinControl(g->child), enabled); -} - -uiDarwinControlDefaultSetSuperview(uiGroup, box) - -static void groupRelayout(uiGroup *g) -{ - NSView *childView; - - removeConstraints(g); - if (g->child == NULL) - return; - childView = (NSView *) uiControlHandle(g->child); - singleChildConstraintsEstablish(&(g->constraints), - [g->box contentView], childView, - uiDarwinControlHugsTrailingEdge(uiDarwinControl(g->child)), - uiDarwinControlHugsBottom(uiDarwinControl(g->child)), - g->margined, - @"uiGroup"); - // needed for some very rare drawing errors... - jiggleViewLayout(g->box); -} - -// TODO rename these since I'm starting to get confused by what they mean by hugging -BOOL uiGroupHugsTrailingEdge(uiDarwinControl *c) -{ - uiGroup *g = uiGroup(c); - - // TODO make a function? - return g->horzHuggingPri < NSLayoutPriorityWindowSizeStayPut; -} - -BOOL uiGroupHugsBottom(uiDarwinControl *c) -{ - uiGroup *g = uiGroup(c); - - return g->vertHuggingPri < NSLayoutPriorityWindowSizeStayPut; -} - -static void uiGroupChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiGroup *g = uiGroup(c); - - groupRelayout(g); -} - -static NSLayoutPriority uiGroupHuggingPriority(uiDarwinControl *c, NSLayoutConstraintOrientation orientation) -{ - uiGroup *g = uiGroup(c); - - if (orientation == NSLayoutConstraintOrientationHorizontal) - return g->horzHuggingPri; - return g->vertHuggingPri; -} - -static void uiGroupSetHuggingPriority(uiDarwinControl *c, NSLayoutPriority priority, NSLayoutConstraintOrientation orientation) -{ - uiGroup *g = uiGroup(c); - - if (orientation == NSLayoutConstraintOrientationHorizontal) - g->horzHuggingPri = priority; - else - g->vertHuggingPri = priority; - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(g)); -} - -static void uiGroupChildVisibilityChanged(uiDarwinControl *c) -{ - uiGroup *g = uiGroup(c); - - groupRelayout(g); -} - -char *uiGroupTitle(uiGroup *g) -{ - return uiDarwinNSStringToText([g->box title]); -} - -void uiGroupSetTitle(uiGroup *g, const char *title) -{ - [g->box setTitle:toNSString(title)]; -} - -void uiGroupSetChild(uiGroup *g, uiControl *child) -{ - NSView *childView; - - if (g->child != NULL) { - removeConstraints(g); - uiDarwinControlSetHuggingPriority(uiDarwinControl(g->child), g->oldHorzHuggingPri, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(g->child), g->oldVertHuggingPri, NSLayoutConstraintOrientationVertical); - uiControlSetParent(g->child, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(g->child), nil); - } - g->child = child; - if (g->child != NULL) { - childView = (NSView *) uiControlHandle(g->child); - uiControlSetParent(g->child, uiControl(g)); - uiDarwinControlSetSuperview(uiDarwinControl(g->child), [g->box contentView]); - uiDarwinControlSyncEnableState(uiDarwinControl(g->child), uiControlEnabledToUser(uiControl(g))); - // don't hug, just in case we're a stretchy group - g->oldHorzHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(g->child), NSLayoutConstraintOrientationHorizontal); - g->oldVertHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(g->child), NSLayoutConstraintOrientationVertical); - uiDarwinControlSetHuggingPriority(uiDarwinControl(g->child), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(g->child), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationVertical); - } - groupRelayout(g); -} - -int uiGroupMargined(uiGroup *g) -{ - return g->margined; -} - -void uiGroupSetMargined(uiGroup *g, int margined) -{ - g->margined = margined; - singleChildConstraintsSetMargined(&(g->constraints), g->margined); -} - -uiGroup *uiNewGroup(const char *title) -{ - uiGroup *g; - - uiDarwinNewControl(uiGroup, g); - - g->box = [[NSBox alloc] initWithFrame:NSZeroRect]; - [g->box setTitle:toNSString(title)]; - [g->box setBoxType:NSBoxPrimary]; - [g->box setBorderType:NSLineBorder]; - [g->box setTransparent:NO]; - [g->box setTitlePosition:NSAtTop]; - // we can't use uiDarwinSetControlFont() because the selector is different - [g->box setTitleFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; - - // default to low hugging to not hug edges - g->horzHuggingPri = NSLayoutPriorityDefaultLow; - g->vertHuggingPri = NSLayoutPriorityDefaultLow; - - return g; -} diff --git a/deps/libui/darwin/image.m b/deps/libui/darwin/image.m deleted file mode 100644 index b62de31d8c..0000000000 --- a/deps/libui/darwin/image.m +++ /dev/null @@ -1,82 +0,0 @@ -// 25 june 2016 -#import "uipriv_darwin.h" - -struct uiImage { - NSImage *i; - NSSize size; - NSMutableArray *swizzled; -}; - -uiImage *uiNewImage(double width, double height) -{ - uiImage *i; - - i = uiNew(uiImage); - i->size = NSMakeSize(width, height); - i->i = [[NSImage alloc] initWithSize:i->size]; - i->swizzled = [NSMutableArray new]; - return i; -} - -void uiFreeImage(uiImage *i) -{ - NSValue *v; - - [i->i release]; - // to be safe, do this after releasing the image - for (v in i->swizzled) - uiFree([v pointerValue]); - [i->swizzled release]; - uiFree(i); -} - -void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, int pixelStride) -{ - NSBitmapImageRep *repCalibrated, *repsRGB; - uint8_t *swizzled, *bp, *sp; - int x, y; - unsigned char *pix[1]; - - // OS X demands that R and B are in the opposite order from what we expect - // we must swizzle :( - // LONGTERM test on a big-endian system - swizzled = (uint8_t *) uiAlloc((pixelStride * pixelHeight * 4) * sizeof (uint8_t), "uint8_t[]"); - bp = (uint8_t *) pixels; - sp = swizzled; - for (y = 0; y < pixelHeight * pixelStride; y += pixelStride) - for (x = 0; x < pixelStride; x++) { - sp[0] = bp[2]; - sp[1] = bp[1]; - sp[2] = bp[0]; - sp[3] = bp[3]; - sp += 4; - bp += 4; - } - - pix[0] = (unsigned char *) swizzled; - repCalibrated = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:pix - pixelsWide:pixelWidth - pixelsHigh:pixelHeight - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSCalibratedRGBColorSpace - bitmapFormat:0 - bytesPerRow:pixelStride - bitsPerPixel:32]; - repsRGB = [repCalibrated bitmapImageRepByRetaggingWithColorSpace:[NSColorSpace sRGBColorSpace]]; - [repCalibrated release]; - - [i->i addRepresentation:repsRGB]; - [repsRGB setSize:i->size]; - [repsRGB release]; - - // we need to keep swizzled alive for NSBitmapImageRep - [i->swizzled addObject:[NSValue valueWithPointer:swizzled]]; -} - -NSImage *imageImage(uiImage *i) -{ - return i->i; -} diff --git a/deps/libui/darwin/label.m b/deps/libui/darwin/label.m deleted file mode 100644 index 897bc3ff44..0000000000 --- a/deps/libui/darwin/label.m +++ /dev/null @@ -1,43 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -struct uiLabel { - uiDarwinControl c; - NSTextField *textfield; -}; - -uiDarwinControlAllDefaults(uiLabel, textfield) - -char *uiLabelText(uiLabel *l) -{ - return uiDarwinNSStringToText([l->textfield stringValue]); -} - -void uiLabelSetText(uiLabel *l, const char *text) -{ - [l->textfield setStringValue:toNSString(text)]; -} - -NSTextField *newLabel(NSString *str) -{ - NSTextField *tf; - - tf = [[NSTextField alloc] initWithFrame:NSZeroRect]; - [tf setStringValue:str]; - [tf setEditable:NO]; - [tf setSelectable:NO]; - [tf setDrawsBackground:NO]; - finishNewTextField(tf, NO); - return tf; -} - -uiLabel *uiNewLabel(const char *text) -{ - uiLabel *l; - - uiDarwinNewControl(uiLabel, l); - - l->textfield = newLabel(toNSString(text)); - - return l; -} diff --git a/deps/libui/darwin/main.m b/deps/libui/darwin/main.m deleted file mode 100644 index 59a8683bff..0000000000 --- a/deps/libui/darwin/main.m +++ /dev/null @@ -1,239 +0,0 @@ -// 6 april 2015 -#import "uipriv_darwin.h" - -static BOOL canQuit = NO; -static NSAutoreleasePool *globalPool; -static applicationClass *app; -static appDelegate *delegate; - -static BOOL (^isRunning)(void); -static BOOL stepsIsRunning; - -@implementation applicationClass - -- (void)sendEvent:(NSEvent *)e -{ - if (sendAreaEvents(e) != 0) - return; - [super sendEvent:e]; -} - -// NSColorPanel always sends changeColor: to the first responder regardless of whether there's a target set on it -// we can override it here (see colorbutton.m) -// thanks to mikeash in irc.freenode.net/#macdev for informing me this is how the first responder chain is initiated -// it turns out NSFontManager also sends changeFont: through this; let's inhibit that here too (see fontbutton.m) -- (BOOL)sendAction:(SEL)sel to:(id)to from:(id)from -{ - if (colorButtonInhibitSendAction(sel, from, to)) - return NO; - if (fontButtonInhibitSendAction(sel, from, to)) - return NO; - return [super sendAction:sel to:to from:from]; -} - -// likewise, NSFontManager also sends NSFontPanelValidation messages to the first responder, however it does NOT use sendAction:from:to:! -// instead, it uses this one (thanks swillits in irc.freenode.net/#macdev) -// we also need to override it (see fontbutton.m) -- (id)targetForAction:(SEL)sel to:(id)to from:(id)from -{ - id override; - - if (fontButtonOverrideTargetForAction(sel, from, to, &override)) - return override; - return [super targetForAction:sel to:to from:from]; -} - -// hey look! we're overriding terminate:! -// we're going to make sure we can go back to main() whether Cocoa likes it or not! -// and just how are we going to do that, hm? -// (note: this is called after applicationShouldTerminate:) -- (void)terminate:(id)sender -{ - // yes that's right folks: DO ABSOLUTELY NOTHING. - // the magic is [NSApp run] will just... stop. - - // well let's not do nothing; let's actually quit our graceful way - NSEvent *e; - - if (!canQuit) - implbug("call to [NSApp terminate:] when not ready to terminate; definitely contact andlabs"); - - [realNSApp() stop:realNSApp()]; - // stop: won't register until another event has passed; let's synthesize one - e = [NSEvent otherEventWithType:NSApplicationDefined - location:NSZeroPoint - modifierFlags:0 - timestamp:[[NSProcessInfo processInfo] systemUptime] - windowNumber:0 - context:[NSGraphicsContext currentContext] - subtype:0 - data1:0 - data2:0]; - [realNSApp() postEvent:e atStart:NO]; // let pending events take priority (this is what PostQuitMessage() on Windows does so we have to do it here too for parity; thanks to mikeash in irc.freenode.net/#macdev for confirming that this parameter should indeed be NO) - - // and in case uiMainSteps() was called - stepsIsRunning = NO; -} - -@end - -@implementation appDelegate - -- (void)dealloc -{ - // Apple docs: "Don't Use Accessor Methods in Initializer Methods and dealloc" - [_menuManager release]; - [super dealloc]; -} - -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app -{ - // for debugging - NSLog(@"in applicationShouldTerminate:"); - if (shouldQuit()) { - canQuit = YES; - // this will call terminate:, which is the same as uiQuit() - return NSTerminateNow; - } - return NSTerminateCancel; -} - -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app -{ - return NO; -} - -@end - -uiInitOptions options; - -const char *uiInit(uiInitOptions *o) -{ - @autoreleasepool { - options = *o; - app = [[applicationClass sharedApplication] retain]; - // don't check for a NO return; something (launch services?) causes running from application bundles to always return NO when asking to change activation policy, even if the change is to the same activation policy! - // see https://github.com/andlabs/ui/issues/6 - [realNSApp() setActivationPolicy:NSApplicationActivationPolicyRegular]; - delegate = [appDelegate new]; - [realNSApp() setDelegate:delegate]; - - initAlloc(); - - // always do this so we always have an application menu - appDelegate().menuManager = [[menuManager new] autorelease]; - [realNSApp() setMainMenu:[appDelegate().menuManager makeMenubar]]; - - setupFontPanel(); - } - - globalPool = [[NSAutoreleasePool alloc] init]; - - return NULL; -} - -void uiUninit(void) -{ - if (!globalPool) { - userbug("You must call uiInit() first!"); - } - [globalPool release]; - - @autoreleasepool { - [delegate release]; - [realNSApp() setDelegate:nil]; - [app release]; - uninitAlloc(); - } -} - -void uiFreeInitError(const char *err) -{ -} - -void uiMain(void) -{ - isRunning = ^{ - return [realNSApp() isRunning]; - }; - [realNSApp() run]; -} - -void uiMainSteps(void) -{ - // SDL does this and it seems to be necessary for the menubar to work (see #182) - [realNSApp() finishLaunching]; - isRunning = ^{ - return stepsIsRunning; - }; - stepsIsRunning = YES; -} - -int uiMainStep(int wait) -{ - struct nextEventArgs nea; - - nea.mask = NSAnyEventMask; - - // ProPuke did this in his original PR requesting this - // I'm not sure if this will work, but I assume it will... - nea.duration = [NSDate distantPast]; - if (wait) // but this is normal so it will work - nea.duration = [NSDate distantFuture]; - - nea.mode = NSDefaultRunLoopMode; - nea.dequeue = YES; - - return mainStep(&nea, ^(NSEvent *e) { - return NO; - }); -} - -// see also: -// - http://www.cocoawithlove.com/2009/01/demystifying-nsapplication-by.html -// - https://github.com/gnustep/gui/blob/master/Source/NSApplication.m -int mainStep(struct nextEventArgs *nea, BOOL (^interceptEvent)(NSEvent *e)) -{ - NSDate *expire; - NSEvent *e; - NSEventType type; - - @autoreleasepool { - if (!isRunning()) - return 0; - - e = [realNSApp() nextEventMatchingMask:nea->mask - untilDate:nea->duration - inMode:nea->mode - dequeue:nea->dequeue]; - if (e == nil) - return 1; - - type = [e type]; - if (!interceptEvent(e)) - [realNSApp() sendEvent:e]; - [realNSApp() updateWindows]; - - // GNUstep does this - // it also updates the Services menu but there doesn't seem to be a public API for that so - if (type != NSPeriodic && type != NSMouseMoved) - [[realNSApp() mainMenu] update]; - - return 1; - } -} - -void uiQuit(void) -{ - canQuit = YES; - [realNSApp() terminate:realNSApp()]; -} - -// thanks to mikeash in irc.freenode.net/#macdev for suggesting the use of Grand Central Dispatch for this -// LONGTERM will dispatch_get_main_queue() break after _CFRunLoopSetCurrent()? -void uiQueueMain(void (*f)(void *data), void *data) -{ - // dispatch_get_main_queue() is a serial queue so it will not execute multiple uiQueueMain() functions concurrently - // the signature of f matches dispatch_function_t - dispatch_async_f(dispatch_get_main_queue(), data, f); -} diff --git a/deps/libui/darwin/map.m b/deps/libui/darwin/map.m deleted file mode 100644 index 46a7b8d242..0000000000 --- a/deps/libui/darwin/map.m +++ /dev/null @@ -1,59 +0,0 @@ -// 17 august 2015 -#import "uipriv_darwin.h" - -// unfortunately NSMutableDictionary copies its keys, meaning we can't use it for pointers -// hence, this file -// we could expose a NSMapTable directly, but let's treat all pointers as opaque and hide the implementation, just to be safe and prevent even more rewrites later -struct mapTable { - NSMapTable *m; -}; - -struct mapTable *newMap(void) -{ - struct mapTable *m; - - m = uiNew(struct mapTable); - m->m = [[NSMapTable alloc] initWithKeyOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality) - valueOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality) - capacity:0]; - return m; -} - -void mapDestroy(struct mapTable *m) -{ - if ([m->m count] != 0) - implbug("attempt to destroy map with items inside"); - [m->m release]; - uiFree(m); -} - -void *mapGet(struct mapTable *m, void *key) -{ - return NSMapGet(m->m, key); -} - -void mapSet(struct mapTable *m, void *key, void *value) -{ - NSMapInsert(m->m, key, value); -} - -void mapDelete(struct mapTable *m, void *key) -{ - NSMapRemove(m->m, key); -} - -void mapWalk(struct mapTable *m, void (*f)(void *key, void *value)) -{ - NSMapEnumerator e = NSEnumerateMapTable(m->m); - void *k = NULL; - void *v = NULL; - while (NSNextMapEnumeratorPair(&e, &k, &v)) { - f(k, v); - } - NSEndMapTableEnumeration(&e); -} - -void mapReset(struct mapTable *m) -{ - NSResetMapTable(m->m); -} diff --git a/deps/libui/darwin/menu.m b/deps/libui/darwin/menu.m deleted file mode 100644 index 735cac5052..0000000000 --- a/deps/libui/darwin/menu.m +++ /dev/null @@ -1,368 +0,0 @@ -// 28 april 2015 -#import "uipriv_darwin.h" - -static NSMutableArray *menus = nil; -static BOOL menusFinalized = NO; - -struct uiMenu { - NSMenu *menu; - NSMenuItem *item; - NSMutableArray *items; -}; - -struct uiMenuItem { - NSMenuItem *item; - int type; - BOOL disabled; - void (*onClicked)(uiMenuItem *, uiWindow *, void *); - void *onClickedData; -}; - -enum { - typeRegular, - typeCheckbox, - typeQuit, - typePreferences, - typeAbout, - typeSeparator, -}; - -static void mapItemReleaser(void *key, void *value) -{ - uiMenuItem *item; - - item = (uiMenuItem *)value; - [item->item release]; -} - -@implementation menuManager - -- (id)init -{ - self = [super init]; - if (self) { - self->items = newMap(); - self->hasQuit = NO; - self->hasPreferences = NO; - self->hasAbout = NO; - } - return self; -} - -- (void)dealloc -{ - mapWalk(self->items, mapItemReleaser); - mapReset(self->items); - mapDestroy(self->items); - uninitMenus(); - [super dealloc]; -} - -- (IBAction)onClicked:(id)sender -{ - uiMenuItem *item; - - item = (uiMenuItem *) mapGet(self->items, sender); - if (item->type == typeCheckbox) - uiMenuItemSetChecked(item, !uiMenuItemChecked(item)); - // use the key window as the source of the menu event; it's the active window - (*(item->onClicked))(item, windowFromNSWindow([realNSApp() keyWindow]), item->onClickedData); -} - -- (IBAction)onQuitClicked:(id)sender -{ - if (shouldQuit()) - uiQuit(); -} - -- (void)register:(NSMenuItem *)item to:(uiMenuItem *)smi -{ - switch (smi->type) { - case typeQuit: - if (self->hasQuit) - userbug("You can't have multiple Quit menu items in one program."); - self->hasQuit = YES; - break; - case typePreferences: - if (self->hasPreferences) - userbug("You can't have multiple Preferences menu items in one program."); - self->hasPreferences = YES; - break; - case typeAbout: - if (self->hasAbout) - userbug("You can't have multiple About menu items in one program."); - self->hasAbout = YES; - break; - } - mapSet(self->items, item, smi); -} - -// on OS X there are two ways to handle menu items being enabled or disabled: automatically and manually -// unfortunately, the application menu requires automatic menu handling for the Hide, Hide Others, and Show All items to work correctly -// therefore, we have to handle enabling of the other options ourselves -- (BOOL)validateMenuItem:(NSMenuItem *)item -{ - uiMenuItem *smi; - - // disable the special items if they aren't present - if (item == self.quitItem && !self->hasQuit) - return NO; - if (item == self.preferencesItem && !self->hasPreferences) - return NO; - if (item == self.aboutItem && !self->hasAbout) - return NO; - // then poll the item's enabled/disabled state - smi = (uiMenuItem *) mapGet(self->items, item); - return !smi->disabled; -} - -// Cocoa constructs the default application menu by hand for each program; that's what MainMenu.[nx]ib does -- (void)buildApplicationMenu:(NSMenu *)menubar -{ - NSString *appName; - NSMenuItem *appMenuItem; - NSMenu *appMenu; - NSMenuItem *item; - NSString *title; - NSMenu *servicesMenu; - - // note: no need to call setAppleMenu: on this anymore; see https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKitOlderNotes/#X10_6Notes - appName = [[NSProcessInfo processInfo] processName]; - appMenuItem = [[[NSMenuItem alloc] initWithTitle:appName action:NULL keyEquivalent:@""] autorelease]; - appMenu = [[[NSMenu alloc] initWithTitle:appName] autorelease]; - [appMenuItem setSubmenu:appMenu]; - [menubar addItem:appMenuItem]; - - // first is About - title = [@"About " stringByAppendingString:appName]; - item = [[[NSMenuItem alloc] initWithTitle:title action:@selector(onClicked:) keyEquivalent:@""] autorelease]; - [item setTarget:self]; - [appMenu addItem:item]; - self.aboutItem = item; - - [appMenu addItem:[NSMenuItem separatorItem]]; - - // next is Preferences - item = [[[NSMenuItem alloc] initWithTitle:@"Preferences…" action:@selector(onClicked:) keyEquivalent:@","] autorelease]; - [item setTarget:self]; - [appMenu addItem:item]; - self.preferencesItem = item; - - [appMenu addItem:[NSMenuItem separatorItem]]; - - // next is Services - item = [[[NSMenuItem alloc] initWithTitle:@"Services" action:NULL keyEquivalent:@""] autorelease]; - servicesMenu = [[[NSMenu alloc] initWithTitle:@"Services"] autorelease]; - [item setSubmenu:servicesMenu]; - [realNSApp() setServicesMenu:servicesMenu]; - [appMenu addItem:item]; - - [appMenu addItem:[NSMenuItem separatorItem]]; - - // next are the three hiding options - title = [@"Hide " stringByAppendingString:appName]; - item = [[[NSMenuItem alloc] initWithTitle:title action:@selector(hide:) keyEquivalent:@"h"] autorelease]; - // the .xib file says they go to -1 ("First Responder", which sounds wrong...) - // to do that, we simply leave the target as nil - [appMenu addItem:item]; - item = [[[NSMenuItem alloc] initWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"] autorelease]; - [item setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)]; - [appMenu addItem:item]; - item = [[[NSMenuItem alloc] initWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""] autorelease]; - [appMenu addItem:item]; - - [appMenu addItem:[NSMenuItem separatorItem]]; - - // and finally Quit - // DON'T use @selector(terminate:) as the action; we handle termination ourselves - title = [@"Quit " stringByAppendingString:appName]; - item = [[[NSMenuItem alloc] initWithTitle:title action:@selector(onQuitClicked:) keyEquivalent:@"q"] autorelease]; - [item setTarget:self]; - [appMenu addItem:item]; - self.quitItem = item; -} - -- (NSMenu *)makeMenubar -{ - NSMenu *menubar; - - menubar = [[[NSMenu alloc] initWithTitle:@""] autorelease]; - [self buildApplicationMenu:menubar]; - return menubar; -} - -@end - -static void defaultOnClicked(uiMenuItem *item, uiWindow *w, void *data) -{ - // do nothing -} - -void uiMenuItemEnable(uiMenuItem *item) -{ - item->disabled = NO; - // we don't need to explicitly update the menus here; they'll be updated the next time they're opened (thanks mikeash in irc.freenode.net/#macdev) -} - -void uiMenuItemDisable(uiMenuItem *item) -{ - item->disabled = YES; -} - -void uiMenuItemOnClicked(uiMenuItem *item, void (*f)(uiMenuItem *, uiWindow *, void *), void *data) -{ - if (item->type == typeQuit) - userbug("You can't call uiMenuItemOnClicked() on a Quit item; use uiOnShouldQuit() instead."); - item->onClicked = f; - item->onClickedData = data; -} - -int uiMenuItemChecked(uiMenuItem *item) -{ - return [item->item state] != NSOffState; -} - -void uiMenuItemSetChecked(uiMenuItem *item, int checked) -{ - NSInteger state; - - state = NSOffState; - if ([item->item state] == NSOffState) - state = NSOnState; - [item->item setState:state]; -} - -static uiMenuItem *newItem(uiMenu *m, int type, const char *name) -{ - @autoreleasepool { - - uiMenuItem *item; - - if (menusFinalized) - userbug("You can't create a new menu item after menus have been finalized."); - - item = uiNew(uiMenuItem); - - item->type = type; - switch (item->type) { - case typeQuit: - item->item = [appDelegate().menuManager.quitItem retain]; - break; - case typePreferences: - item->item = [appDelegate().menuManager.preferencesItem retain]; - break; - case typeAbout: - item->item = [appDelegate().menuManager.aboutItem retain]; - break; - case typeSeparator: - item->item = [[NSMenuItem separatorItem] retain]; - [m->menu addItem:item->item]; - break; - default: - item->item = [[NSMenuItem alloc] initWithTitle:toNSString(name) action:@selector(onClicked:) keyEquivalent:@""]; - [item->item setTarget:appDelegate().menuManager]; - [m->menu addItem:item->item]; - break; - } - - [appDelegate().menuManager register:item->item to:item]; - item->onClicked = defaultOnClicked; - - [m->items addObject:[NSValue valueWithPointer:item]]; - - return item; - - } // @autoreleasepool -} - -uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name) -{ - return newItem(m, typeRegular, name); -} - -uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name) -{ - return newItem(m, typeCheckbox, name); -} - -uiMenuItem *uiMenuAppendQuitItem(uiMenu *m) -{ - // duplicate check is in the register:to: selector - return newItem(m, typeQuit, NULL); -} - -uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m) -{ - // duplicate check is in the register:to: selector - return newItem(m, typePreferences, NULL); -} - -uiMenuItem *uiMenuAppendAboutItem(uiMenu *m) -{ - // duplicate check is in the register:to: selector - return newItem(m, typeAbout, NULL); -} - -void uiMenuAppendSeparator(uiMenu *m) -{ - newItem(m, typeSeparator, NULL); -} - -uiMenu *uiNewMenu(const char *name) -{ - @autoreleasepool { - - uiMenu *m; - - if (menusFinalized) - userbug("You can't create a new menu after menus have been finalized."); - if (menus == nil) - menus = [NSMutableArray new]; - - m = uiNew(uiMenu); - - m->menu = [[NSMenu alloc] initWithTitle:toNSString(name)]; - // use automatic menu item enabling for all menus for consistency's sake - - m->item = [[NSMenuItem alloc] initWithTitle:toNSString(name) action:NULL keyEquivalent:@""]; - [m->item setSubmenu:m->menu]; - - m->items = [NSMutableArray new]; - - [[realNSApp() mainMenu] addItem:m->item]; - - [menus addObject:[NSValue valueWithPointer:m]]; - - return m; - - } // @autoreleasepool -} - -void finalizeMenus(void) -{ - menusFinalized = YES; -} - -void uninitMenus(void) -{ - if (menus == NULL) - return; - [menus enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) { - NSValue *v; - uiMenu *m; - - v = (NSValue *) obj; - m = (uiMenu *) [v pointerValue]; - [m->items enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) { - NSValue *v; - uiMenuItem *mi; - - v = (NSValue *) obj; - mi = (uiMenuItem *) [v pointerValue]; - uiFree(mi); - }]; - [m->items release]; - uiFree(m); - }]; - [menus release]; -} diff --git a/deps/libui/darwin/multilineentry.m b/deps/libui/darwin/multilineentry.m deleted file mode 100644 index 605e90041f..0000000000 --- a/deps/libui/darwin/multilineentry.m +++ /dev/null @@ -1,233 +0,0 @@ -// 8 december 2015 -#import "uipriv_darwin.h" - -// NSTextView has no intrinsic content size by default, which wreaks havoc on a pure-Auto Layout system -// we'll have to take over to get it to work -// see also http://stackoverflow.com/questions/24210153/nstextview-not-properly-resizing-with-auto-layout and http://stackoverflow.com/questions/11237622/using-autolayout-with-expanding-nstextviews -@interface intrinsicSizeTextView : NSTextView { - uiMultilineEntry *libui_e; -} -- (id)initWithFrame:(NSRect)r e:(uiMultilineEntry *)e; -@end - -struct uiMultilineEntry { - uiDarwinControl c; - NSScrollView *sv; - intrinsicSizeTextView *tv; - struct scrollViewData *d; - void (*onChanged)(uiMultilineEntry *, void *); - void *onChangedData; - BOOL changing; -}; - -@implementation intrinsicSizeTextView - -- (id)initWithFrame:(NSRect)r e:(uiMultilineEntry *)e -{ - self = [super initWithFrame:r]; - if (self) - self->libui_e = e; - return self; -} - -- (NSSize)intrinsicContentSize -{ - NSTextContainer *textContainer; - NSLayoutManager *layoutManager; - NSRect rect; - - textContainer = [self textContainer]; - layoutManager = [self layoutManager]; - [layoutManager ensureLayoutForTextContainer:textContainer]; - rect = [layoutManager usedRectForTextContainer:textContainer]; - return rect.size; -} - -- (void)didChangeText -{ - [super didChangeText]; - [self invalidateIntrinsicContentSize]; - if (!self->libui_e->changing) - (*(self->libui_e->onChanged))(self->libui_e, self->libui_e->onChangedData); -} - -@end - -uiDarwinControlAllDefaultsExceptDestroy(uiMultilineEntry, sv) - -static void uiMultilineEntryDestroy(uiControl *c) -{ - uiMultilineEntry *e = uiMultilineEntry(c); - - scrollViewFreeData(e->sv, e->d); - [e->tv release]; - [e->sv release]; - uiFreeControl(uiControl(e)); -} - -static void defaultOnChanged(uiMultilineEntry *e, void *data) -{ - // do nothing -} - -char *uiMultilineEntryText(uiMultilineEntry *e) -{ - return uiDarwinNSStringToText([e->tv string]); -} - -void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text) -{ - [[e->tv textStorage] replaceCharactersInRange:NSMakeRange(0, [[e->tv string] length]) - withString:toNSString(text)]; - // must be called explicitly according to the documentation of shouldChangeTextInRange:replacementString: - e->changing = YES; - [e->tv didChangeText]; - e->changing = NO; -} - -// TODO scroll to end? -void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text) -{ - [[e->tv textStorage] replaceCharactersInRange:NSMakeRange([[e->tv string] length], 0) - withString:toNSString(text)]; - e->changing = YES; - [e->tv didChangeText]; - e->changing = NO; -} - -void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *e, void *data), void *data) -{ - e->onChanged = f; - e->onChangedData = data; -} - -int uiMultilineEntryReadOnly(uiMultilineEntry *e) -{ - return [e->tv isEditable] == NO; -} - -void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly) -{ - BOOL editable; - - editable = YES; - if (readonly) - editable = NO; - [e->tv setEditable:editable]; -} - -static uiMultilineEntry *finishMultilineEntry(BOOL hscroll) -{ - uiMultilineEntry *e; - NSFont *font; - struct scrollViewCreateParams p; - - uiDarwinNewControl(uiMultilineEntry, e); - - e->tv = [[intrinsicSizeTextView alloc] initWithFrame:NSZeroRect e:e]; - - // verified against Interface Builder for a sufficiently customized text view - - // NSText properties: - // this is what Interface Builder sets the background color to - [e->tv setBackgroundColor:[NSColor colorWithCalibratedWhite:1.0 alpha:1.0]]; - [e->tv setDrawsBackground:YES]; - [e->tv setEditable:YES]; - [e->tv setSelectable:YES]; - [e->tv setFieldEditor:NO]; - [e->tv setRichText:NO]; - [e->tv setImportsGraphics:NO]; - [e->tv setUsesFontPanel:NO]; - [e->tv setRulerVisible:NO]; - // we'll handle font last - // while setAlignment: has been around since 10.0, the named constant "NSTextAlignmentNatural" seems to have only been introduced in 10.11 -#define ourNSTextAlignmentNatural 4 - [e->tv setAlignment:ourNSTextAlignmentNatural]; - // textColor is set to nil, just keep the dfault - [e->tv setBaseWritingDirection:NSWritingDirectionNatural]; - [e->tv setHorizontallyResizable:NO]; - [e->tv setVerticallyResizable:YES]; - - // NSTextView properties: - [e->tv setAllowsDocumentBackgroundColorChange:NO]; - [e->tv setAllowsUndo:YES]; - // default paragraph style is nil; keep default - [e->tv setAllowsImageEditing:NO]; - [e->tv setAutomaticQuoteSubstitutionEnabled:NO]; - [e->tv setAutomaticLinkDetectionEnabled:NO]; - [e->tv setDisplaysLinkToolTips:YES]; - [e->tv setUsesRuler:NO]; - [e->tv setUsesInspectorBar:NO]; - [e->tv setSelectionGranularity:NSSelectByCharacter]; - // there is a dedicated named insertion point color but oh well - [e->tv setInsertionPointColor:[NSColor controlTextColor]]; - // typing attributes is nil; keep default (we change it below for fonts though) - [e->tv setSmartInsertDeleteEnabled:NO]; - [e->tv setContinuousSpellCheckingEnabled:NO]; - [e->tv setGrammarCheckingEnabled:NO]; - [e->tv setUsesFindPanel:YES]; - [e->tv setEnabledTextCheckingTypes:0]; - [e->tv setAutomaticDashSubstitutionEnabled:NO]; - [e->tv setAutomaticDataDetectionEnabled:NO]; - [e->tv setAutomaticSpellingCorrectionEnabled:NO]; - [e->tv setAutomaticTextReplacementEnabled:NO]; - [e->tv setUsesFindBar:NO]; - [e->tv setIncrementalSearchingEnabled:NO]; - - // NSTextContainer properties: - [[e->tv textContainer] setWidthTracksTextView:YES]; - [[e->tv textContainer] setHeightTracksTextView:NO]; - - // NSLayoutManager properties: - [[e->tv layoutManager] setAllowsNonContiguousLayout:YES]; - - // now just to be safe; this will do some of the above but whatever - disableAutocorrect(e->tv); - - // see https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/TextUILayer/Tasks/TextInScrollView.html - // notice we don't use the Auto Layout code; see scrollview.m for more details - [e->tv setMaxSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX)]; - [e->tv setVerticallyResizable:YES]; - [e->tv setHorizontallyResizable:hscroll]; - if (hscroll) { - [e->tv setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; - [[e->tv textContainer] setWidthTracksTextView:NO]; - } else { - [e->tv setAutoresizingMask:NSViewWidthSizable]; - [[e->tv textContainer] setWidthTracksTextView:YES]; - } - [[e->tv textContainer] setContainerSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX)]; - - // don't use uiDarwinSetControlFont() directly; we have to do a little extra work to set the font - font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; - [e->tv setTypingAttributes:[NSDictionary - dictionaryWithObject:font - forKey:NSFontAttributeName]]; - // e->tv font from Interface Builder is nil, but setFont:nil throws an exception - // let's just set it to the standard control font anyway, just to be safe - [e->tv setFont:font]; - - memset(&p, 0, sizeof (struct scrollViewCreateParams)); - p.DocumentView = e->tv; - // this is what Interface Builder sets it to - p.BackgroundColor = [NSColor colorWithCalibratedWhite:1.0 alpha:1.0]; - p.DrawsBackground = YES; - p.Bordered = YES; - p.HScroll = hscroll; - p.VScroll = YES; - e->sv = mkScrollView(&p, &(e->d)); - - uiMultilineEntryOnChanged(e, defaultOnChanged, NULL); - - return e; -} - -uiMultilineEntry *uiNewMultilineEntry(void) -{ - return finishMultilineEntry(NO); -} - -uiMultilineEntry *uiNewNonWrappingMultilineEntry(void) -{ - return finishMultilineEntry(YES); -} diff --git a/deps/libui/darwin/progressbar.m b/deps/libui/darwin/progressbar.m deleted file mode 100644 index b538228195..0000000000 --- a/deps/libui/darwin/progressbar.m +++ /dev/null @@ -1,78 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// NSProgressIndicator has no intrinsic width by default; use the default width in Interface Builder -#define progressIndicatorWidth 100 - -@interface intrinsicWidthNSProgressIndicator : NSProgressIndicator -@end - -@implementation intrinsicWidthNSProgressIndicator - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = progressIndicatorWidth; - return s; -} - -@end - -struct uiProgressBar { - uiDarwinControl c; - NSProgressIndicator *pi; -}; - -uiDarwinControlAllDefaults(uiProgressBar, pi) - -int uiProgressBarValue(uiProgressBar *p) -{ - if ([p->pi isIndeterminate]) - return -1; - return [p->pi doubleValue]; -} - -void uiProgressBarSetValue(uiProgressBar *p, int value) -{ - if (value == -1) { - [p->pi setIndeterminate:YES]; - [p->pi startAnimation:p->pi]; - return; - } - - if ([p->pi isIndeterminate]) { - [p->pi setIndeterminate:NO]; - [p->pi stopAnimation:p->pi]; - } - - if (value < 0 || value > 100) - userbug("Value %d out of range for a uiProgressBar.", value); - - // on 10.8 there's an animation when the progress bar increases, just like with Aero - if (value == 100) { - [p->pi setMaxValue:101]; - [p->pi setDoubleValue:101]; - [p->pi setDoubleValue:100]; - [p->pi setMaxValue:100]; - return; - } - [p->pi setDoubleValue:((double) (value + 1))]; - [p->pi setDoubleValue:((double) value)]; -} - -uiProgressBar *uiNewProgressBar(void) -{ - uiProgressBar *p; - - uiDarwinNewControl(uiProgressBar, p); - - p->pi = [[intrinsicWidthNSProgressIndicator alloc] initWithFrame:NSZeroRect]; - [p->pi setControlSize:NSRegularControlSize]; - [p->pi setBezeled:YES]; - [p->pi setStyle:NSProgressIndicatorBarStyle]; - [p->pi setIndeterminate:NO]; - - return p; -} diff --git a/deps/libui/darwin/radiobuttons.m b/deps/libui/darwin/radiobuttons.m deleted file mode 100644 index 25d773c972..0000000000 --- a/deps/libui/darwin/radiobuttons.m +++ /dev/null @@ -1,207 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// TODO resizing the controlgallery vertically causes the third button to still resize :| - -// In the old days you would use a NSMatrix for this; as of OS X 10.8 this was deprecated and now you need just a bunch of NSButtons with the same superview AND same action method. -// This is documented on the NSMatrix page, but the rest of the OS X documentation says to still use NSMatrix. -// NSMatrix has weird quirks anyway... - -// LONGTERM 6 units of spacing between buttons, as suggested by Interface Builder? - -@interface radioButtonsDelegate : NSObject { - uiRadioButtons *libui_r; -} -- (id)initWithR:(uiRadioButtons *)r; -- (IBAction)onClicked:(id)sender; -@end - -struct uiRadioButtons { - uiDarwinControl c; - NSView *view; - NSMutableArray *buttons; - NSMutableArray *constraints; - NSLayoutConstraint *lastv; - radioButtonsDelegate *delegate; - void (*onSelected)(uiRadioButtons *, void *); - void *onSelectedData; -}; - -@implementation radioButtonsDelegate - -- (id)initWithR:(uiRadioButtons *)r -{ - self = [super init]; - if (self) - self->libui_r = r; - return self; -} - -- (IBAction)onClicked:(id)sender -{ - uiRadioButtons *r = self->libui_r; - - (*(r->onSelected))(r, r->onSelectedData); -} - -@end - -uiDarwinControlAllDefaultsExceptDestroy(uiRadioButtons, view) - -static void defaultOnSelected(uiRadioButtons *r, void *data) -{ - // do nothing -} - -static void uiRadioButtonsDestroy(uiControl *c) -{ - uiRadioButtons *r = uiRadioButtons(c); - NSButton *b; - - // drop the constraints - [r->view removeConstraints:r->constraints]; - [r->constraints release]; - if (r->lastv != nil) - [r->lastv release]; - // destroy the buttons - for (b in r->buttons) { - [b setTarget:nil]; - [b removeFromSuperview]; - } - [r->buttons release]; - // destroy the delegate - [r->delegate release]; - // and destroy ourselves - [r->view release]; - uiFreeControl(uiControl(r)); -} - -static NSButton *buttonAt(uiRadioButtons *r, int n) -{ - return (NSButton *) [r->buttons objectAtIndex:n]; -} - -void uiRadioButtonsAppend(uiRadioButtons *r, const char *text) -{ - NSButton *b, *b2; - NSLayoutConstraint *constraint; - - b = [[NSButton alloc] initWithFrame:NSZeroRect]; - [b setTitle:toNSString(text)]; - [b setButtonType:NSRadioButton]; - // doesn't seem to have an associated bezel style - [b setBordered:NO]; - [b setTransparent:NO]; - uiDarwinSetControlFont(b, NSRegularControlSize); - [b setTranslatesAutoresizingMaskIntoConstraints:NO]; - - [b setTarget:r->delegate]; - [b setAction:@selector(onClicked:)]; - - [r->buttons addObject:b]; - [r->view addSubview:b]; - - // pin horizontally to the edges of the superview - constraint = mkConstraint(b, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - r->view, NSLayoutAttributeLeading, - 1, 0, - @"uiRadioButtons button leading constraint"); - [r->view addConstraint:constraint]; - [r->constraints addObject:constraint]; - constraint = mkConstraint(b, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - r->view, NSLayoutAttributeTrailing, - 1, 0, - @"uiRadioButtons button trailing constraint"); - [r->view addConstraint:constraint]; - [r->constraints addObject:constraint]; - - // if this is the first view, pin it to the top - // otherwise pin to the bottom of the last - if ([r->buttons count] == 1) - constraint = mkConstraint(b, NSLayoutAttributeTop, - NSLayoutRelationEqual, - r->view, NSLayoutAttributeTop, - 1, 0, - @"uiRadioButtons first button top constraint"); - else { - b2 = buttonAt(r, [r->buttons count] - 2); - constraint = mkConstraint(b, NSLayoutAttributeTop, - NSLayoutRelationEqual, - b2, NSLayoutAttributeBottom, - 1, 0, - @"uiRadioButtons non-first button top constraint"); - } - [r->view addConstraint:constraint]; - [r->constraints addObject:constraint]; - - // if there is a previous bottom constraint, remove it - if (r->lastv != nil) { - [r->view removeConstraint:r->lastv]; - [r->constraints removeObject:r->lastv]; - [r->lastv release]; - } - - // and make the new bottom constraint - r->lastv = mkConstraint(b, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - r->view, NSLayoutAttributeBottom, - 1, 0, - @"uiRadioButtons last button bottom constraint"); - [r->view addConstraint:r->lastv]; - [r->constraints addObject:r->lastv]; - [r->lastv retain]; -} - -int uiRadioButtonsSelected(uiRadioButtons *r) -{ - NSButton *b; - NSUInteger i; - - for (i = 0; i < [r->buttons count]; i++) { - b = (NSButton *) [r->buttons objectAtIndex:i]; - if ([b state] == NSOnState) - return i; - } - return -1; -} - -void uiRadioButtonsSetSelected(uiRadioButtons *r, int n) -{ - NSButton *b; - NSInteger state; - - state = NSOnState; - if (n == -1) { - n = uiRadioButtonsSelected(r); - if (n == -1) // from nothing to nothing; do nothing - return; - state = NSOffState; - } - b = (NSButton *) [r->buttons objectAtIndex:n]; - [b setState:state]; -} - -void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data) -{ - r->onSelected = f; - r->onSelectedData = data; -} - -uiRadioButtons *uiNewRadioButtons(void) -{ - uiRadioButtons *r; - - uiDarwinNewControl(uiRadioButtons, r); - - r->view = [[NSView alloc] initWithFrame:NSZeroRect]; - r->buttons = [NSMutableArray new]; - r->constraints = [NSMutableArray new]; - - r->delegate = [[radioButtonsDelegate alloc] initWithR:r]; - - uiRadioButtonsOnSelected(r, defaultOnSelected, NULL); - - return r; -} diff --git a/deps/libui/darwin/scrollview.m b/deps/libui/darwin/scrollview.m deleted file mode 100644 index b0b4040c3a..0000000000 --- a/deps/libui/darwin/scrollview.m +++ /dev/null @@ -1,61 +0,0 @@ -// 27 may 2016 -#include "uipriv_darwin.h" - -// see http://stackoverflow.com/questions/37979445/how-do-i-properly-set-up-a-scrolling-nstableview-using-auto-layout-what-ive-tr for why we don't use auto layout -// TODO do the same with uiGroup and uiTab? - -struct scrollViewData { - BOOL hscroll; - BOOL vscroll; -}; - -NSScrollView *mkScrollView(struct scrollViewCreateParams *p, struct scrollViewData **dout) -{ - NSScrollView *sv; - NSBorderType border; - struct scrollViewData *d; - - sv = [[NSScrollView alloc] initWithFrame:NSZeroRect]; - if (p->BackgroundColor != nil) - [sv setBackgroundColor:p->BackgroundColor]; - [sv setDrawsBackground:p->DrawsBackground]; - border = NSNoBorder; - if (p->Bordered) - border = NSBezelBorder; - // document view seems to set the cursor properly - [sv setBorderType:border]; - [sv setAutohidesScrollers:YES]; - [sv setHasHorizontalRuler:NO]; - [sv setHasVerticalRuler:NO]; - [sv setRulersVisible:NO]; - [sv setScrollerKnobStyle:NSScrollerKnobStyleDefault]; - // the scroller style is documented as being set by default for us - // LONGTERM verify line and page for programmatically created NSTableView - [sv setScrollsDynamically:YES]; - [sv setFindBarPosition:NSScrollViewFindBarPositionAboveContent]; - [sv setUsesPredominantAxisScrolling:NO]; - [sv setHorizontalScrollElasticity:NSScrollElasticityAutomatic]; - [sv setVerticalScrollElasticity:NSScrollElasticityAutomatic]; - [sv setAllowsMagnification:NO]; - - [sv setDocumentView:p->DocumentView]; - d = uiNew(struct scrollViewData); - scrollViewSetScrolling(sv, d, p->HScroll, p->VScroll); - - *dout = d; - return sv; -} - -// based on http://blog.bjhomer.com/2014/08/nsscrollview-and-autolayout.html because (as pointed out there) Apple's official guide is really only for iOS -void scrollViewSetScrolling(NSScrollView *sv, struct scrollViewData *d, BOOL hscroll, BOOL vscroll) -{ - d->hscroll = hscroll; - [sv setHasHorizontalScroller:d->hscroll]; - d->vscroll = vscroll; - [sv setHasVerticalScroller:d->vscroll]; -} - -void scrollViewFreeData(NSScrollView *sv, struct scrollViewData *d) -{ - uiFree(d); -} diff --git a/deps/libui/darwin/separator.m b/deps/libui/darwin/separator.m deleted file mode 100644 index a37a376e75..0000000000 --- a/deps/libui/darwin/separator.m +++ /dev/null @@ -1,45 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// TODO make this intrinsic -#define separatorWidth 96 -#define separatorHeight 96 - -struct uiSeparator { - uiDarwinControl c; - NSBox *box; -}; - -uiDarwinControlAllDefaults(uiSeparator, box) - -uiSeparator *uiNewHorizontalSeparator(void) -{ - uiSeparator *s; - - uiDarwinNewControl(uiSeparator, s); - - // make the initial width >= initial height to force horizontal - s->box = [[NSBox alloc] initWithFrame:NSMakeRect(0, 0, 100, 1)]; - [s->box setBoxType:NSBoxSeparator]; - [s->box setBorderType:NSGrooveBorder]; - [s->box setTransparent:NO]; - [s->box setTitlePosition:NSNoTitle]; - - return s; -} - -uiSeparator *uiNewVerticalSeparator(void) -{ - uiSeparator *s; - - uiDarwinNewControl(uiSeparator, s); - - // make the initial height >= initial width to force vertical - s->box = [[NSBox alloc] initWithFrame:NSMakeRect(0, 0, 1, 100)]; - [s->box setBoxType:NSBoxSeparator]; - [s->box setBorderType:NSGrooveBorder]; - [s->box setTransparent:NO]; - [s->box setTitlePosition:NSNoTitle]; - - return s; -} diff --git a/deps/libui/darwin/slider.m b/deps/libui/darwin/slider.m deleted file mode 100644 index f00da50fdd..0000000000 --- a/deps/libui/darwin/slider.m +++ /dev/null @@ -1,147 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// Horizontal sliders have no intrinsic width; we'll use the default Interface Builder width for them. -// This will also be used for the initial frame size, to ensure the slider is always horizontal (see below). -#define sliderWidth 92 - -@interface libui_intrinsicWidthNSSlider : NSSlider -@end - -@implementation libui_intrinsicWidthNSSlider - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = sliderWidth; - return s; -} - -@end - -struct uiSlider { - uiDarwinControl c; - NSSlider *slider; - void (*onChanged)(uiSlider *, void *); - void *onChangedData; -}; - -@interface sliderDelegateClass : NSObject { - struct mapTable *sliders; -} -- (IBAction)onChanged:(id)sender; -- (void)registerSlider:(uiSlider *)b; -- (void)unregisterSlider:(uiSlider *)b; -@end - -@implementation sliderDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->sliders = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->sliders); - [super dealloc]; -} - -- (IBAction)onChanged:(id)sender -{ - uiSlider *s; - - s = (uiSlider *) mapGet(self->sliders, sender); - (*(s->onChanged))(s, s->onChangedData); -} - -- (void)registerSlider:(uiSlider *)s -{ - mapSet(self->sliders, s->slider, s); - [s->slider setTarget:self]; - [s->slider setAction:@selector(onChanged:)]; -} - -- (void)unregisterSlider:(uiSlider *)s -{ - [s->slider setTarget:nil]; - mapDelete(self->sliders, s->slider); -} - -@end - -static sliderDelegateClass *sliderDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiSlider, slider) - -static void uiSliderDestroy(uiControl *c) -{ - uiSlider *s = uiSlider(c); - - [sliderDelegate unregisterSlider:s]; - [s->slider release]; - uiFreeControl(uiControl(s)); -} - -int uiSliderValue(uiSlider *s) -{ - return [s->slider integerValue]; -} - -void uiSliderSetValue(uiSlider *s, int value) -{ - [s->slider setIntegerValue:value]; -} - -void uiSliderOnChanged(uiSlider *s, void (*f)(uiSlider *, void *), void *data) -{ - s->onChanged = f; - s->onChangedData = data; -} - -static void defaultOnChanged(uiSlider *s, void *data) -{ - // do nothing -} - -uiSlider *uiNewSlider(int min, int max) -{ - uiSlider *s; - NSSliderCell *cell; - int temp; - - if (min >= max) { - temp = min; - min = max; - max = temp; - } - - uiDarwinNewControl(uiSlider, s); - - // a horizontal slider is defined as one where the width > height, not by a flag - // to be safe, don't use NSZeroRect, but make it horizontal from the get-go - s->slider = [[libui_intrinsicWidthNSSlider alloc] - initWithFrame:NSMakeRect(0, 0, sliderWidth, 2)]; - [s->slider setMinValue:min]; - [s->slider setMaxValue:max]; - [s->slider setAllowsTickMarkValuesOnly:NO]; - [s->slider setNumberOfTickMarks:0]; - [s->slider setTickMarkPosition:NSTickMarkAbove]; - - cell = (NSSliderCell *) [s->slider cell]; - [cell setSliderType:NSLinearSlider]; - - if (sliderDelegate == nil) { - sliderDelegate = [[sliderDelegateClass new] autorelease]; - [delegates addObject:sliderDelegate]; - } - [sliderDelegate registerSlider:s]; - uiSliderOnChanged(s, defaultOnChanged, NULL); - - return s; -} diff --git a/deps/libui/darwin/spinbox.m b/deps/libui/darwin/spinbox.m deleted file mode 100644 index 73474d04e0..0000000000 --- a/deps/libui/darwin/spinbox.m +++ /dev/null @@ -1,214 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -@interface libui_spinbox : NSView { - NSTextField *tf; - NSNumberFormatter *formatter; - NSStepper *stepper; - - NSInteger value; - NSInteger minimum; - NSInteger maximum; - - uiSpinbox *spinbox; -} -- (id)initWithFrame:(NSRect)r spinbox:(uiSpinbox *)sb; -// see https://github.com/andlabs/ui/issues/82 -- (NSInteger)libui_value; -- (void)libui_setValue:(NSInteger)val; -- (void)setMinimum:(NSInteger)min; -- (void)setMaximum:(NSInteger)max; -- (IBAction)stepperClicked:(id)sender; -- (void)controlTextDidChange:(NSNotification *)note; -@end - -struct uiSpinbox { - uiDarwinControl c; - libui_spinbox *spinbox; - void (*onChanged)(uiSpinbox *, void *); - void *onChangedData; -}; - -// yes folks, this varies by operating system! woo! -// 10.10 started drawing the NSStepper one point too low, so we have to fix it up conditionally -// TODO test this; we'll probably have to substitute 10_9 -static CGFloat stepperYDelta(void) -{ - // via https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKit/ - if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9) - return 0; - return -1; -} - -@implementation libui_spinbox - -- (id)initWithFrame:(NSRect)r spinbox:(uiSpinbox *)sb -{ - self = [super initWithFrame:r]; - if (self) { - self->tf = newEditableTextField(); - [self->tf setTranslatesAutoresizingMaskIntoConstraints:NO]; - - self->formatter = [NSNumberFormatter new]; - [self->formatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; - [self->formatter setLocalizesFormat:NO]; - [self->formatter setUsesGroupingSeparator:NO]; - [self->formatter setHasThousandSeparators:NO]; - [self->formatter setAllowsFloats:NO]; - [self->tf setFormatter:self->formatter]; - - self->stepper = [[NSStepper alloc] initWithFrame:NSZeroRect]; - [self->stepper setIncrement:1]; - [self->stepper setValueWraps:NO]; - [self->stepper setAutorepeat:YES]; // hold mouse button to step repeatedly - [self->stepper setTranslatesAutoresizingMaskIntoConstraints:NO]; - - [self->tf setDelegate:self]; - [self->stepper setTarget:self]; - [self->stepper setAction:@selector(stepperClicked:)]; - - [self addSubview:self->tf]; - [self addSubview:self->stepper]; - - [self addConstraint:mkConstraint(self->tf, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - self, NSLayoutAttributeLeading, - 1, 0, - @"uiSpinbox left edge")]; - [self addConstraint:mkConstraint(self->stepper, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - self, NSLayoutAttributeTrailing, - 1, 0, - @"uiSpinbox right edge")]; - [self addConstraint:mkConstraint(self->tf, NSLayoutAttributeTop, - NSLayoutRelationEqual, - self, NSLayoutAttributeTop, - 1, 0, - @"uiSpinbox top edge text field")]; - [self addConstraint:mkConstraint(self->tf, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - self, NSLayoutAttributeBottom, - 1, 0, - @"uiSpinbox bottom edge text field")]; - [self addConstraint:mkConstraint(self->stepper, NSLayoutAttributeTop, - NSLayoutRelationEqual, - self, NSLayoutAttributeTop, - 1, stepperYDelta(), - @"uiSpinbox top edge stepper")]; - [self addConstraint:mkConstraint(self->stepper, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - self, NSLayoutAttributeBottom, - 1, stepperYDelta(), - @"uiSpinbox bottom edge stepper")]; - [self addConstraint:mkConstraint(self->tf, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - self->stepper, NSLayoutAttributeLeading, - 1, -3, // arbitrary amount; good enough visually (and it seems to match NSDatePicker too, at least on 10.11, which is even better) - @"uiSpinbox space between text field and stepper")]; - - self->spinbox = sb; - } - return self; -} - -- (void)dealloc -{ - [self->tf setDelegate:nil]; - [self->tf removeFromSuperview]; - [self->tf release]; - [self->formatter release]; - [self->stepper setTarget:nil]; - [self->stepper removeFromSuperview]; - [self->stepper release]; - [super dealloc]; -} - -- (NSInteger)libui_value -{ - return self->value; -} - -- (void)libui_setValue:(NSInteger)val -{ - self->value = val; - if (self->value < self->minimum) - self->value = self->minimum; - if (self->value > self->maximum) - self->value = self->maximum; - [self->tf setIntegerValue:self->value]; - [self->stepper setIntegerValue:self->value]; -} - -- (void)setMinimum:(NSInteger)min -{ - self->minimum = min; - [self->formatter setMinimum:[NSNumber numberWithInteger:self->minimum]]; - [self->stepper setMinValue:((double) (self->minimum))]; -} - -- (void)setMaximum:(NSInteger)max -{ - self->maximum = max; - [self->formatter setMaximum:[NSNumber numberWithInteger:self->maximum]]; - [self->stepper setMaxValue:((double) (self->maximum))]; -} - -- (IBAction)stepperClicked:(id)sender -{ - [self libui_setValue:[self->stepper integerValue]]; - (*(self->spinbox->onChanged))(self->spinbox, self->spinbox->onChangedData); -} - -- (void)controlTextDidChange:(NSNotification *)note -{ - [self libui_setValue:[self->tf integerValue]]; - (*(self->spinbox->onChanged))(self->spinbox, self->spinbox->onChangedData); -} - -@end - -uiDarwinControlAllDefaults(uiSpinbox, spinbox) - -int uiSpinboxValue(uiSpinbox *s) -{ - return [s->spinbox libui_value]; -} - -void uiSpinboxSetValue(uiSpinbox *s, int value) -{ - [s->spinbox libui_setValue:value]; -} - -void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *, void *), void *data) -{ - s->onChanged = f; - s->onChangedData = data; -} - -static void defaultOnChanged(uiSpinbox *s, void *data) -{ - // do nothing -} - -uiSpinbox *uiNewSpinbox(int min, int max) -{ - uiSpinbox *s; - int temp; - - if (min >= max) { - temp = min; - min = max; - max = temp; - } - - uiDarwinNewControl(uiSpinbox, s); - - s->spinbox = [[libui_spinbox alloc] initWithFrame:NSZeroRect spinbox:s]; - [s->spinbox setMinimum:min]; - [s->spinbox setMaximum:max]; - [s->spinbox libui_setValue:min]; - - uiSpinboxOnChanged(s, defaultOnChanged, NULL); - - return s; -} diff --git a/deps/libui/darwin/stddialogs.m b/deps/libui/darwin/stddialogs.m deleted file mode 100644 index 57ce9596ad..0000000000 --- a/deps/libui/darwin/stddialogs.m +++ /dev/null @@ -1,123 +0,0 @@ -// 26 june 2015 -#import "uipriv_darwin.h" - -// LONGTERM restructure this whole file -// LONGTERM explicitly document this works as we want -// LONGTERM note that font and color buttons also do this - -#define windowWindow(w) ((NSWindow *) uiControlHandle(uiControl(w))) - -// source of code modal logic: http://stackoverflow.com/questions/604768/wait-for-nsalert-beginsheetmodalforwindow - -// note: whether extensions are actually shown depends on a user setting in Finder; we can't control it here -static void setupSavePanel(NSSavePanel *s) -{ - [s setCanCreateDirectories:YES]; - [s setShowsHiddenFiles:YES]; - [s setExtensionHidden:NO]; - [s setCanSelectHiddenExtension:NO]; - [s setTreatsFilePackagesAsDirectories:YES]; -} - -static char *runSavePanel(NSWindow *parent, NSSavePanel *s) -{ - char *filename; - - [s beginSheetModalForWindow:parent completionHandler:^(NSInteger result) { - [realNSApp() stopModalWithCode:result]; - }]; - if ([realNSApp() runModalForWindow:s] != NSFileHandlingPanelOKButton) - return NULL; - filename = uiDarwinNSStringToText([[s URL] path]); - return filename; -} - -char *uiOpenFile(uiWindow *parent) -{ - NSOpenPanel *o; - - o = [NSOpenPanel openPanel]; - [o setCanChooseFiles:YES]; - [o setCanChooseDirectories:NO]; - [o setResolvesAliases:NO]; - [o setAllowsMultipleSelection:NO]; - setupSavePanel(o); - // panel is autoreleased - return runSavePanel(windowWindow(parent), o); -} - -char *uiSaveFile(uiWindow *parent) -{ - NSSavePanel *s; - - s = [NSSavePanel savePanel]; - setupSavePanel(s); - // panel is autoreleased - return runSavePanel(windowWindow(parent), s); -} - -// I would use a completion handler for NSAlert as well, but alas NSAlert's are 10.9 and higher only -@interface libuiCodeModalAlertPanel : NSObject { - NSAlert *panel; - NSWindow *parent; -} -- (id)initWithPanel:(NSAlert *)p parent:(NSWindow *)w; -- (NSInteger)run; -- (void)panelEnded:(NSAlert *)panel result:(NSInteger)result data:(void *)data; -@end - -@implementation libuiCodeModalAlertPanel - -- (id)initWithPanel:(NSAlert *)p parent:(NSWindow *)w -{ - self = [super init]; - if (self) { - self->panel = p; - self->parent = w; - } - return self; -} - -- (NSInteger)run -{ - [self->panel beginSheetModalForWindow:self->parent - modalDelegate:self - didEndSelector:@selector(panelEnded:result:data:) - contextInfo:NULL]; - return [realNSApp() runModalForWindow:[self->panel window]]; -} - -- (void)panelEnded:(NSAlert *)panel result:(NSInteger)result data:(void *)data -{ - [realNSApp() stopModalWithCode:result]; -} - -@end - -static void msgbox(NSWindow *parent, const char *title, const char *description, NSAlertStyle style) -{ - NSAlert *a; - libuiCodeModalAlertPanel *cm; - - a = [NSAlert new]; - [a setAlertStyle:style]; - [a setShowsHelp:NO]; - [a setShowsSuppressionButton:NO]; - [a setMessageText:toNSString(title)]; - [a setInformativeText:toNSString(description)]; - [a addButtonWithTitle:@"OK"]; - cm = [[libuiCodeModalAlertPanel alloc] initWithPanel:a parent:parent]; - [cm run]; - [cm release]; - [a release]; -} - -void uiMsgBox(uiWindow *parent, const char *title, const char *description) -{ - msgbox(windowWindow(parent), title, description, NSInformationalAlertStyle); -} - -void uiMsgBoxError(uiWindow *parent, const char *title, const char *description) -{ - msgbox(windowWindow(parent), title, description, NSCriticalAlertStyle); -} diff --git a/deps/libui/darwin/tab.m b/deps/libui/darwin/tab.m deleted file mode 100644 index 3d2ca9f0d0..0000000000 --- a/deps/libui/darwin/tab.m +++ /dev/null @@ -1,292 +0,0 @@ -// 15 august 2015 -#import "uipriv_darwin.h" - -// TODO need to jiggle on tab change too (second page disabled tab label initially ambiguous) - -@interface tabPage : NSObject { - struct singleChildConstraints constraints; - int margined; - NSView *view; // the NSTabViewItem view itself - NSObject *pageID; -} -@property uiControl *c; -@property NSLayoutPriority oldHorzHuggingPri; -@property NSLayoutPriority oldVertHuggingPri; -- (id)initWithView:(NSView *)v pageID:(NSObject *)o; -- (NSView *)childView; -- (void)establishChildConstraints; -- (void)removeChildConstraints; -- (int)isMargined; -- (void)setMargined:(int)m; -@end - -struct uiTab { - uiDarwinControl c; - NSTabView *tabview; - NSMutableArray *pages; - NSLayoutPriority horzHuggingPri; - NSLayoutPriority vertHuggingPri; -}; - -@implementation tabPage - -- (id)initWithView:(NSView *)v pageID:(NSObject *)o -{ - self = [super init]; - if (self != nil) { - self->view = [v retain]; - self->pageID = [o retain]; - } - return self; -} - -- (void)dealloc -{ - [self removeChildConstraints]; - [self->view release]; - [self->pageID release]; - [super dealloc]; -} - -- (NSView *)childView -{ - return (NSView *) uiControlHandle(self.c); -} - -- (void)establishChildConstraints -{ - [self removeChildConstraints]; - if (self.c == NULL) - return; - singleChildConstraintsEstablish(&(self->constraints), - self->view, [self childView], - uiDarwinControlHugsTrailingEdge(uiDarwinControl(self.c)), - uiDarwinControlHugsBottom(uiDarwinControl(self.c)), - self->margined, - @"uiTab page"); -} - -- (void)removeChildConstraints -{ - singleChildConstraintsRemove(&(self->constraints), self->view); -} - -- (int)isMargined -{ - return self->margined; -} - -- (void)setMargined:(int)m -{ - self->margined = m; - singleChildConstraintsSetMargined(&(self->constraints), self->margined); -} - -@end - -static void uiTabDestroy(uiControl *c) -{ - uiTab *t = uiTab(c); - tabPage *page; - - // first remove all tab pages so we can destroy all the children - while ([t->tabview numberOfTabViewItems] != 0) - [t->tabview removeTabViewItem:[t->tabview tabViewItemAtIndex:0]]; - // then destroy all the children - for (page in t->pages) { - [page removeChildConstraints]; - uiControlSetParent(page.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(page.c), nil); - uiControlDestroy(page.c); - } - // and finally destroy ourselves - [t->pages release]; - [t->tabview release]; - uiFreeControl(uiControl(t)); -} - -uiDarwinControlDefaultHandle(uiTab, tabview) -uiDarwinControlDefaultParent(uiTab, tabview) -uiDarwinControlDefaultSetParent(uiTab, tabview) -uiDarwinControlDefaultToplevel(uiTab, tabview) -uiDarwinControlDefaultVisible(uiTab, tabview) -uiDarwinControlDefaultShow(uiTab, tabview) -uiDarwinControlDefaultHide(uiTab, tabview) -uiDarwinControlDefaultEnabled(uiTab, tabview) -uiDarwinControlDefaultEnable(uiTab, tabview) -uiDarwinControlDefaultDisable(uiTab, tabview) - -static void uiTabSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiTab *t = uiTab(c); - tabPage *page; - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(t), enabled)) - return; - for (page in t->pages) - uiDarwinControlSyncEnableState(uiDarwinControl(page.c), enabled); -} - -uiDarwinControlDefaultSetSuperview(uiTab, tabview) - -static void tabRelayout(uiTab *t) -{ - tabPage *page; - - for (page in t->pages) - [page establishChildConstraints]; - // and this gets rid of some weird issues with regards to box alignment - jiggleViewLayout(t->tabview); -} - -BOOL uiTabHugsTrailingEdge(uiDarwinControl *c) -{ - uiTab *t = uiTab(c); - - return t->horzHuggingPri < NSLayoutPriorityWindowSizeStayPut; -} - -BOOL uiTabHugsBottom(uiDarwinControl *c) -{ - uiTab *t = uiTab(c); - - return t->vertHuggingPri < NSLayoutPriorityWindowSizeStayPut; -} - -static void uiTabChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiTab *t = uiTab(c); - - tabRelayout(t); -} - -static NSLayoutPriority uiTabHuggingPriority(uiDarwinControl *c, NSLayoutConstraintOrientation orientation) -{ - uiTab *t = uiTab(c); - - if (orientation == NSLayoutConstraintOrientationHorizontal) - return t->horzHuggingPri; - return t->vertHuggingPri; -} - -static void uiTabSetHuggingPriority(uiDarwinControl *c, NSLayoutPriority priority, NSLayoutConstraintOrientation orientation) -{ - uiTab *t = uiTab(c); - - if (orientation == NSLayoutConstraintOrientationHorizontal) - t->horzHuggingPri = priority; - else - t->vertHuggingPri = priority; - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(t)); -} - -static void uiTabChildVisibilityChanged(uiDarwinControl *c) -{ - uiTab *t = uiTab(c); - - tabRelayout(t); -} - -void uiTabAppend(uiTab *t, const char *name, uiControl *child) -{ - uiTabInsertAt(t, name, [t->pages count], child); -} - -void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) -{ - tabPage *page; - NSView *view; - NSTabViewItem *i; - NSObject *pageID; - - uiControlSetParent(child, uiControl(t)); - - view = [[[NSView alloc] initWithFrame:NSZeroRect] autorelease]; - // note: if we turn off the autoresizing mask, nothing shows up - uiDarwinControlSetSuperview(uiDarwinControl(child), view); - uiDarwinControlSyncEnableState(uiDarwinControl(child), uiControlEnabledToUser(uiControl(t))); - - // the documentation says these can be nil but the headers say these must not be; let's be safe and make them non-nil anyway - pageID = [NSObject new]; - page = [[[tabPage alloc] initWithView:view pageID:pageID] autorelease]; - page.c = child; - - // don't hug, just in case we're a stretchy tab - page.oldHorzHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(page.c), NSLayoutConstraintOrientationHorizontal); - page.oldVertHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(page.c), NSLayoutConstraintOrientationVertical); - uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationVertical); - - [t->pages insertObject:page atIndex:n]; - - i = [[[NSTabViewItem alloc] initWithIdentifier:pageID] autorelease]; - [i setLabel:toNSString(name)]; - [i setView:view]; - [t->tabview insertTabViewItem:i atIndex:n]; - - tabRelayout(t); -} - -void uiTabDelete(uiTab *t, int n) -{ - tabPage *page; - uiControl *child; - NSTabViewItem *i; - - page = (tabPage *) [t->pages objectAtIndex:n]; - - uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), page.oldHorzHuggingPri, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), page.oldVertHuggingPri, NSLayoutConstraintOrientationVertical); - - child = page.c; - [page removeChildConstraints]; - [t->pages removeObjectAtIndex:n]; - - uiControlSetParent(child, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(child), nil); - - i = [t->tabview tabViewItemAtIndex:n]; - [t->tabview removeTabViewItem:i]; - - tabRelayout(t); -} - -int uiTabNumPages(uiTab *t) -{ - return [t->pages count]; -} - -int uiTabMargined(uiTab *t, int n) -{ - tabPage *page; - - page = (tabPage *) [t->pages objectAtIndex:n]; - return [page isMargined]; -} - -void uiTabSetMargined(uiTab *t, int n, int margined) -{ - tabPage *page; - - page = (tabPage *) [t->pages objectAtIndex:n]; - [page setMargined:margined]; -} - -uiTab *uiNewTab(void) -{ - uiTab *t; - - uiDarwinNewControl(uiTab, t); - - t->tabview = [[NSTabView alloc] initWithFrame:NSZeroRect]; - // also good for NSTabView (same selector and everything) - uiDarwinSetControlFont((NSControl *) (t->tabview), NSRegularControlSize); - - t->pages = [NSMutableArray new]; - - // default to low hugging to not hug edges - t->horzHuggingPri = NSLayoutPriorityDefaultLow; - t->vertHuggingPri = NSLayoutPriorityDefaultLow; - - return t; -} diff --git a/deps/libui/darwin/text.m b/deps/libui/darwin/text.m deleted file mode 100644 index f0d3dab69e..0000000000 --- a/deps/libui/darwin/text.m +++ /dev/null @@ -1,19 +0,0 @@ -// 10 april 2015 -#import "uipriv_darwin.h" - -char *uiDarwinNSStringToText(NSString *s) -{ - char *out; - - out = strdup([s UTF8String]); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiDarwinNSStringToText()\n"); - abort(); - } - return out; -} - -void uiFreeText(char *s) -{ - free(s); -} diff --git a/deps/libui/darwin/uipriv_darwin.h b/deps/libui/darwin/uipriv_darwin.h deleted file mode 100644 index 6bca87b269..0000000000 --- a/deps/libui/darwin/uipriv_darwin.h +++ /dev/null @@ -1,146 +0,0 @@ -// 6 january 2015 -#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_8 -#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_8 -#import -#import "../ui.h" -#import "../ui_darwin.h" -#import "../common/uipriv.h" - -#if __has_feature(objc_arc) -#error Sorry, libui cannot be compiled with ARC. -#endif - -#define toNSString(str) [NSString stringWithUTF8String:(str)] -#define fromNSString(str) [(str) UTF8String] - -#ifndef NSAppKitVersionNumber10_9 -#define NSAppKitVersionNumber10_9 1265 -#endif - -/*TODO remove this*/typedef struct uiImage uiImage; - -// menu.m -@interface menuManager : NSObject { - struct mapTable *items; - BOOL hasQuit; - BOOL hasPreferences; - BOOL hasAbout; -} -@property (strong) NSMenuItem *quitItem; -@property (strong) NSMenuItem *preferencesItem; -@property (strong) NSMenuItem *aboutItem; -// NSMenuValidation is only informal -- (BOOL)validateMenuItem:(NSMenuItem *)item; -- (NSMenu *)makeMenubar; -@end -extern void finalizeMenus(void); -extern void uninitMenus(void); - -// main.m -@interface applicationClass : NSApplication -@end -// this is needed because NSApp is of type id, confusing clang -#define realNSApp() ((applicationClass *) NSApp) -@interface appDelegate : NSObject -@property (strong) menuManager *menuManager; -@end -#define appDelegate() ((appDelegate *) [realNSApp() delegate]) -struct nextEventArgs { - NSEventMask mask; - NSDate *duration; - // LONGTERM no NSRunLoopMode? - NSString *mode; - BOOL dequeue; -}; -extern int mainStep(struct nextEventArgs *nea, BOOL (^interceptEvent)(NSEvent *)); - -// util.m -extern void disableAutocorrect(NSTextView *); - -// entry.m -extern void finishNewTextField(NSTextField *, BOOL); -extern NSTextField *newEditableTextField(void); - -// window.m -@interface libuiNSWindow : NSWindow -- (void)libui_doMove:(NSEvent *)initialEvent; -- (void)libui_doResize:(NSEvent *)initialEvent on:(uiWindowResizeEdge)edge; -@end -extern uiWindow *windowFromNSWindow(NSWindow *); - -// alloc.m -extern NSMutableArray *delegates; -extern void initAlloc(void); -extern void uninitAlloc(void); - -// autolayout.m -extern NSLayoutConstraint *mkConstraint(id view1, NSLayoutAttribute attr1, NSLayoutRelation relation, id view2, NSLayoutAttribute attr2, CGFloat multiplier, CGFloat c, NSString *desc); -extern void jiggleViewLayout(NSView *view); -struct singleChildConstraints { - NSLayoutConstraint *leadingConstraint; - NSLayoutConstraint *topConstraint; - NSLayoutConstraint *trailingConstraintGreater; - NSLayoutConstraint *trailingConstraintEqual; - NSLayoutConstraint *bottomConstraintGreater; - NSLayoutConstraint *bottomConstraintEqual; -}; -extern void singleChildConstraintsEstablish(struct singleChildConstraints *c, NSView *contentView, NSView *childView, BOOL hugsTrailing, BOOL hugsBottom, int margined, NSString *desc); -extern void singleChildConstraintsRemove(struct singleChildConstraints *c, NSView *cv); -extern void singleChildConstraintsSetMargined(struct singleChildConstraints *c, int margined); - -// map.m -extern struct mapTable *newMap(void); -extern void mapDestroy(struct mapTable *m); -extern void *mapGet(struct mapTable *m, void *key); -extern void mapSet(struct mapTable *m, void *key, void *value); -extern void mapDelete(struct mapTable *m, void *key); -extern void mapWalk(struct mapTable *m, void (*f)(void *key, void *value)); -extern void mapReset(struct mapTable *m); - -// area.m -extern int sendAreaEvents(NSEvent *); - -// areaevents.m -extern BOOL fromKeycode(unsigned short keycode, uiAreaKeyEvent *ke); -extern BOOL keycodeModifier(unsigned short keycode, uiModifiers *mod); - -// draw.m -extern uiDrawContext *newContext(CGContextRef, CGFloat); -extern void freeContext(uiDrawContext *); - -// drawtext.m -extern uiDrawTextFont *mkTextFont(CTFontRef f, BOOL retain); -extern uiDrawTextFont *mkTextFontFromNSFont(NSFont *f); -extern void doDrawText(CGContextRef c, CGFloat cheight, double x, double y, uiDrawTextLayout *layout); - -// fontbutton.m -extern BOOL fontButtonInhibitSendAction(SEL sel, id from, id to); -extern BOOL fontButtonOverrideTargetForAction(SEL sel, id from, id to, id *override); -extern void setupFontPanel(void); - -// colorbutton.m -extern BOOL colorButtonInhibitSendAction(SEL sel, id from, id to); - -// scrollview.m -struct scrollViewCreateParams { - NSView *DocumentView; - NSColor *BackgroundColor; - BOOL DrawsBackground; - BOOL Bordered; - BOOL HScroll; - BOOL VScroll; -}; -struct scrollViewData; -extern NSScrollView *mkScrollView(struct scrollViewCreateParams *p, struct scrollViewData **dout); -extern void scrollViewSetScrolling(NSScrollView *sv, struct scrollViewData *d, BOOL hscroll, BOOL vscroll); -extern void scrollViewFreeData(NSScrollView *sv, struct scrollViewData *d); - -// label.m -extern NSTextField *newLabel(NSString *str); - -// image.m -extern NSImage *imageImage(uiImage *); - -// winmoveresize.m -extern void doManualMove(NSWindow *w, NSEvent *initialEvent); -extern void doManualResize(NSWindow *w, NSEvent *initialEvent, uiWindowResizeEdge edge); diff --git a/deps/libui/darwin/util.m b/deps/libui/darwin/util.m deleted file mode 100644 index ab873906d5..0000000000 --- a/deps/libui/darwin/util.m +++ /dev/null @@ -1,15 +0,0 @@ -// 7 april 2015 -#import "uipriv_darwin.h" - -// LONGTERM do we really want to do this? make it an option? -void disableAutocorrect(NSTextView *tv) -{ - [tv setEnabledTextCheckingTypes:0]; - [tv setAutomaticDashSubstitutionEnabled:NO]; - // don't worry about automatic data detection; it won't change stringValue (thanks pretty_function in irc.freenode.net/#macdev) - [tv setAutomaticSpellingCorrectionEnabled:NO]; - [tv setAutomaticTextReplacementEnabled:NO]; - [tv setAutomaticQuoteSubstitutionEnabled:NO]; - [tv setAutomaticLinkDetectionEnabled:NO]; - [tv setSmartInsertDeleteEnabled:NO]; -} diff --git a/deps/libui/darwin/window.m b/deps/libui/darwin/window.m deleted file mode 100644 index 97c22e6229..0000000000 --- a/deps/libui/darwin/window.m +++ /dev/null @@ -1,407 +0,0 @@ -// 15 august 2015 -#import "uipriv_darwin.h" - -#define defaultStyleMask (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) - -struct uiWindow { - uiDarwinControl c; - NSWindow *window; - uiControl *child; - int margined; - int (*onClosing)(uiWindow *, void *); - void *onClosingData; - struct singleChildConstraints constraints; - void (*onContentSizeChanged)(uiWindow *, void *); - void *onContentSizeChangedData; - BOOL suppressSizeChanged; - int fullscreen; - int borderless; -}; - -@implementation libuiNSWindow - -- (void)libui_doMove:(NSEvent *)initialEvent -{ - doManualMove(self, initialEvent); -} - -- (void)libui_doResize:(NSEvent *)initialEvent on:(uiWindowResizeEdge)edge -{ - doManualResize(self, initialEvent, edge); -} - -@end - -@interface windowDelegateClass : NSObject { - struct mapTable *windows; -} -- (BOOL)windowShouldClose:(id)sender; -- (void)windowDidResize:(NSNotification *)note; -- (void)windowDidEnterFullScreen:(NSNotification *)note; -- (void)windowDidExitFullScreen:(NSNotification *)note; -- (void)registerWindow:(uiWindow *)w; -- (void)unregisterWindow:(uiWindow *)w; -- (uiWindow *)lookupWindow:(NSWindow *)w; -@end - -@implementation windowDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->windows = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->windows); - [super dealloc]; -} - -- (BOOL)windowShouldClose:(id)sender -{ - uiWindow *w; - - w = [self lookupWindow:((NSWindow *) sender)]; - // w should not be NULL; we are only the delegate of registered windows - if ((*(w->onClosing))(w, w->onClosingData)) - uiControlDestroy(uiControl(w)); - return NO; -} - -- (void)windowDidResize:(NSNotification *)note -{ - uiWindow *w; - - w = [self lookupWindow:((NSWindow *) [note object])]; - if (!w->suppressSizeChanged) - (*(w->onContentSizeChanged))(w, w->onContentSizeChangedData); -} - -- (void)windowDidEnterFullScreen:(NSNotification *)note -{ - uiWindow *w; - - w = [self lookupWindow:((NSWindow *) [note object])]; - if (!w->suppressSizeChanged) - w->fullscreen = 1; -} - -- (void)windowDidExitFullScreen:(NSNotification *)note -{ - uiWindow *w; - - w = [self lookupWindow:((NSWindow *) [note object])]; - if (!w->suppressSizeChanged) - w->fullscreen = 0; -} - -- (void)registerWindow:(uiWindow *)w -{ - mapSet(self->windows, w->window, w); - [w->window setDelegate:self]; -} - -- (void)unregisterWindow:(uiWindow *)w -{ - [w->window setDelegate:nil]; - mapDelete(self->windows, w->window); -} - -- (uiWindow *)lookupWindow:(NSWindow *)w -{ - uiWindow *v; - - v = uiWindow(mapGet(self->windows, w)); - // this CAN (and IS ALLOWED TO) return NULL, just in case we're called with some OS X-provided window as the key window - return v; -} - -@end - -static windowDelegateClass *windowDelegate = nil; - -static void removeConstraints(uiWindow *w) -{ - NSView *cv; - - cv = [w->window contentView]; - singleChildConstraintsRemove(&(w->constraints), cv); -} - -static void uiWindowDestroy(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - // hide the window - [w->window orderOut:w->window]; - removeConstraints(w); - if (w->child != NULL) { - uiControlSetParent(w->child, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(w->child), nil); - uiControlDestroy(w->child); - } - [windowDelegate unregisterWindow:w]; - [w->window release]; - uiFreeControl(uiControl(w)); -} - -uiDarwinControlDefaultHandle(uiWindow, window) - -uiControl *uiWindowParent(uiControl *c) -{ - return NULL; -} - -void uiWindowSetParent(uiControl *c, uiControl *parent) -{ - uiUserBugCannotSetParentOnToplevel("uiWindow"); -} - -static int uiWindowToplevel(uiControl *c) -{ - return 1; -} - -static int uiWindowVisible(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - return [w->window isVisible]; -} - -static void uiWindowShow(uiControl *c) -{ - uiWindow *w = (uiWindow *) c; - - [w->window makeKeyAndOrderFront:w->window]; -} - -static void uiWindowHide(uiControl *c) -{ - uiWindow *w = (uiWindow *) c; - - [w->window orderOut:w->window]; -} - -uiDarwinControlDefaultEnabled(uiWindow, window) -uiDarwinControlDefaultEnable(uiWindow, window) -uiDarwinControlDefaultDisable(uiWindow, window) - -static void uiWindowSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiWindow *w = uiWindow(c); - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(w), enabled)) - return; - if (w->child != NULL) - uiDarwinControlSyncEnableState(uiDarwinControl(w->child), enabled); -} - -static void uiWindowSetSuperview(uiDarwinControl *c, NSView *superview) -{ - // TODO -} - -static void windowRelayout(uiWindow *w) -{ - NSView *childView; - NSView *contentView; - - removeConstraints(w); - if (w->child == NULL) - return; - childView = (NSView *) uiControlHandle(w->child); - contentView = [w->window contentView]; - singleChildConstraintsEstablish(&(w->constraints), - contentView, childView, - uiDarwinControlHugsTrailingEdge(uiDarwinControl(w->child)), - uiDarwinControlHugsBottom(uiDarwinControl(w->child)), - w->margined, - @"uiWindow"); -} - -uiDarwinControlDefaultHugsTrailingEdge(uiWindow, window) -uiDarwinControlDefaultHugsBottom(uiWindow, window) - -static void uiWindowChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiWindow *w = uiWindow(c); - - windowRelayout(w); -} - -// TODO -uiDarwinControlDefaultHuggingPriority(uiWindow, window) -uiDarwinControlDefaultSetHuggingPriority(uiWindow, window) -// end TODO - -static void uiWindowChildVisibilityChanged(uiDarwinControl *c) -{ - uiWindow *w = uiWindow(c); - - windowRelayout(w); -} - -char *uiWindowTitle(uiWindow *w) -{ - return uiDarwinNSStringToText([w->window title]); -} - -void uiWindowSetTitle(uiWindow *w, const char *title) -{ - [w->window setTitle:toNSString(title)]; -} - -void uiWindowContentSize(uiWindow *w, int *width, int *height) -{ - NSRect r; - - r = [w->window contentRectForFrameRect:[w->window frame]]; - *width = r.size.width; - *height = r.size.height; -} - -void uiWindowSetContentSize(uiWindow *w, int width, int height) -{ - w->suppressSizeChanged = YES; - [w->window setContentSize:NSMakeSize(width, height)]; - w->suppressSizeChanged = NO; -} - -int uiWindowFullscreen(uiWindow *w) -{ - return w->fullscreen; -} - -void uiWindowSetFullscreen(uiWindow *w, int fullscreen) -{ - if (w->fullscreen && fullscreen) - return; - if (!w->fullscreen && !fullscreen) - return; - w->fullscreen = fullscreen; - if (w->fullscreen && w->borderless) // borderless doesn't play nice with fullscreen; don't toggle while borderless - return; - w->suppressSizeChanged = YES; - [w->window toggleFullScreen:w->window]; - w->suppressSizeChanged = NO; - if (!w->fullscreen && w->borderless) // borderless doesn't play nice with fullscreen; restore borderless after removing - [w->window setStyleMask:NSBorderlessWindowMask]; -} - -void uiWindowOnContentSizeChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data) -{ - w->onContentSizeChanged = f; - w->onContentSizeChangedData = data; -} - -void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data) -{ - w->onClosing = f; - w->onClosingData = data; -} - -int uiWindowBorderless(uiWindow *w) -{ - return w->borderless; -} - -void uiWindowSetBorderless(uiWindow *w, int borderless) -{ - w->borderless = borderless; - if (w->borderless) { - // borderless doesn't play nice with fullscreen; wait for later - if (!w->fullscreen) - [w->window setStyleMask:NSBorderlessWindowMask]; - } else { - [w->window setStyleMask:defaultStyleMask]; - // borderless doesn't play nice with fullscreen; restore state - if (w->fullscreen) { - w->suppressSizeChanged = YES; - [w->window toggleFullScreen:w->window]; - w->suppressSizeChanged = NO; - } - } -} - -void uiWindowSetChild(uiWindow *w, uiControl *child) -{ - NSView *childView; - - if (w->child != NULL) { - childView = (NSView *) uiControlHandle(w->child); - [childView removeFromSuperview]; - uiControlSetParent(w->child, NULL); - } - w->child = child; - if (w->child != NULL) { - uiControlSetParent(w->child, uiControl(w)); - childView = (NSView *) uiControlHandle(w->child); - uiDarwinControlSetSuperview(uiDarwinControl(w->child), [w->window contentView]); - uiDarwinControlSyncEnableState(uiDarwinControl(w->child), uiControlEnabledToUser(uiControl(w))); - } - windowRelayout(w); -} - -int uiWindowMargined(uiWindow *w) -{ - return w->margined; -} - -void uiWindowSetMargined(uiWindow *w, int margined) -{ - w->margined = margined; - singleChildConstraintsSetMargined(&(w->constraints), w->margined); -} - -static int defaultOnClosing(uiWindow *w, void *data) -{ - return 0; -} - -static void defaultOnPositionContentSizeChanged(uiWindow *w, void *data) -{ - // do nothing -} - -uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) -{ - uiWindow *w; - - finalizeMenus(); - - uiDarwinNewControl(uiWindow, w); - - w->window = [[libuiNSWindow alloc] initWithContentRect:NSMakeRect(0, 0, (CGFloat) width, (CGFloat) height) - styleMask:defaultStyleMask - backing:NSBackingStoreBuffered - defer:YES]; - [w->window setTitle:toNSString(title)]; - - // do NOT release when closed - // we manually do this in uiWindowDestroy() above - [w->window setReleasedWhenClosed:NO]; - - if (windowDelegate == nil) { - windowDelegate = [[windowDelegateClass new] autorelease]; - [delegates addObject:windowDelegate]; - } - [windowDelegate registerWindow:w]; - uiWindowOnClosing(w, defaultOnClosing, NULL); - uiWindowOnContentSizeChanged(w, defaultOnPositionContentSizeChanged, NULL); - - return w; -} - -// utility function for menus -uiWindow *windowFromNSWindow(NSWindow *w) -{ - if (w == nil) - return NULL; - if (windowDelegate == nil) // no windows were created yet; we're called with some OS X-provided window - return NULL; - return [windowDelegate lookupWindow:w]; -} diff --git a/deps/libui/darwin/winmoveresize.m b/deps/libui/darwin/winmoveresize.m deleted file mode 100644 index 9145b7bb33..0000000000 --- a/deps/libui/darwin/winmoveresize.m +++ /dev/null @@ -1,253 +0,0 @@ -// 1 november 2016 -#import "uipriv_darwin.h" - -// because we are changing the window frame each time the mouse moves, the successive -[NSEvent locationInWindow]s cannot be meaningfully used together -// make sure they are all following some sort of standard to avoid this problem; the screen is the most obvious possibility since it requires only one conversion (the only one that a NSWindow provides) -static NSPoint makeIndependent(NSPoint p, NSWindow *w) -{ - NSRect r; - - r.origin = p; - // mikeash in irc.freenode.net/#macdev confirms both that any size will do and that we can safely ignore the resultant size - r.size = NSZeroSize; - return [w convertRectToScreen:r].origin; -} - -struct onMoveDragParams { - NSWindow *w; - // using the previous point causes weird issues like the mouse seeming to fall behind the window edge... so do this instead - // TODO will this make things like the menubar and dock easier too? - NSRect initialFrame; - NSPoint initialPoint; -}; - -void onMoveDrag(struct onMoveDragParams *p, NSEvent *e) -{ - NSPoint new; - NSRect frame; - CGFloat offx, offy; - - new = makeIndependent([e locationInWindow], p->w); - frame = p->initialFrame; - - offx = new.x - p->initialPoint.x; - offy = new.y - p->initialPoint.y; - frame.origin.x += offx; - frame.origin.y += offy; - - // TODO handle the menubar - // TODO wait the system does this for us already?! - - [p->w setFrameOrigin:frame.origin]; -} - -void doManualMove(NSWindow *w, NSEvent *initialEvent) -{ - __block struct onMoveDragParams mdp; - struct nextEventArgs nea; - BOOL (^handleEvent)(NSEvent *e); - __block BOOL done; - - // this is only available on 10.11 and newer (LONGTERM FUTURE) - // but use it if available; this lets us use the real OS dragging code, which means we can take advantage of OS features like Spaces - if ([w respondsToSelector:@selector(performWindowDragWithEvent:)]) { - [((id) w) performWindowDragWithEvent:initialEvent]; - return; - } - - mdp.w = w; - mdp.initialFrame = [mdp.w frame]; - mdp.initialPoint = makeIndependent([initialEvent locationInWindow], mdp.w); - - nea.mask = NSLeftMouseDraggedMask | NSLeftMouseUpMask; - nea.duration = [NSDate distantFuture]; - nea.mode = NSEventTrackingRunLoopMode; // nextEventMatchingMask: docs suggest using this for manual mouse tracking - nea.dequeue = YES; - handleEvent = ^(NSEvent *e) { - if ([e type] == NSLeftMouseUp) { - done = YES; - return YES; // do not send - } - onMoveDrag(&mdp, e); - return YES; // do not send - }; - done = NO; - while (mainStep(&nea, handleEvent)) - if (done) - break; -} - -// see http://stackoverflow.com/a/40352996/3408572 -static void minMaxAutoLayoutSizes(NSWindow *w, NSSize *min, NSSize *max) -{ - NSLayoutConstraint *cw, *ch; - NSView *contentView; - NSRect prevFrame; - - // if adding these constraints causes the window to change size somehow, don't show it to the user and change it back afterwards - NSDisableScreenUpdates(); - prevFrame = [w frame]; - - // minimum: encourage the window to be as small as possible - contentView = [w contentView]; - cw = mkConstraint(contentView, NSLayoutAttributeWidth, - NSLayoutRelationEqual, - nil, NSLayoutAttributeNotAnAttribute, - 0, 0, - @"window minimum width finding constraint"); - [cw setPriority:NSLayoutPriorityDragThatCanResizeWindow]; - [contentView addConstraint:cw]; - ch = mkConstraint(contentView, NSLayoutAttributeHeight, - NSLayoutRelationEqual, - nil, NSLayoutAttributeNotAnAttribute, - 0, 0, - @"window minimum height finding constraint"); - [ch setPriority:NSLayoutPriorityDragThatCanResizeWindow]; - [contentView addConstraint:ch]; - *min = [contentView fittingSize]; - [contentView removeConstraint:cw]; - [contentView removeConstraint:ch]; - - // maximum: encourage the window to be as large as possible - contentView = [w contentView]; - cw = mkConstraint(contentView, NSLayoutAttributeWidth, - NSLayoutRelationEqual, - nil, NSLayoutAttributeNotAnAttribute, - 0, CGFLOAT_MAX, - @"window maximum width finding constraint"); - [cw setPriority:NSLayoutPriorityDragThatCanResizeWindow]; - [contentView addConstraint:cw]; - ch = mkConstraint(contentView, NSLayoutAttributeHeight, - NSLayoutRelationEqual, - nil, NSLayoutAttributeNotAnAttribute, - 0, CGFLOAT_MAX, - @"window maximum height finding constraint"); - [ch setPriority:NSLayoutPriorityDragThatCanResizeWindow]; - [contentView addConstraint:ch]; - *max = [contentView fittingSize]; - [contentView removeConstraint:cw]; - [contentView removeConstraint:ch]; - - [w setFrame:prevFrame display:YES]; // TODO really YES? - NSEnableScreenUpdates(); -} - -static void handleResizeLeft(NSRect *frame, NSPoint old, NSPoint new) -{ - frame->origin.x += new.x - old.x; - frame->size.width -= new.x - old.x; -} - -// TODO properly handle the menubar -// TODO wait, OS X does it for us?! -static void handleResizeTop(NSRect *frame, NSPoint old, NSPoint new) -{ - frame->size.height += new.y - old.y; -} - -static void handleResizeRight(NSRect *frame, NSPoint old, NSPoint new) -{ - frame->size.width += new.x - old.x; -} - - -// TODO properly handle the menubar -static void handleResizeBottom(NSRect *frame, NSPoint old, NSPoint new) -{ - frame->origin.y += new.y - old.y; - frame->size.height -= new.y - old.y; -} - -struct onResizeDragParams { - NSWindow *w; - // using the previous point causes weird issues like the mouse seeming to fall behind the window edge... so do this instead - // TODO will this make things like the menubar and dock easier too? - NSRect initialFrame; - NSPoint initialPoint; - uiWindowResizeEdge edge; - NSSize min; - NSSize max; -}; - -static void onResizeDrag(struct onResizeDragParams *p, NSEvent *e) -{ - NSPoint new; - NSRect frame; - - new = makeIndependent([e locationInWindow], p->w); - frame = p->initialFrame; - - // horizontal - switch (p->edge) { - case uiWindowResizeEdgeLeft: - case uiWindowResizeEdgeTopLeft: - case uiWindowResizeEdgeBottomLeft: - handleResizeLeft(&frame, p->initialPoint, new); - break; - case uiWindowResizeEdgeRight: - case uiWindowResizeEdgeTopRight: - case uiWindowResizeEdgeBottomRight: - handleResizeRight(&frame, p->initialPoint, new); - break; - } - // vertical - switch (p->edge) { - case uiWindowResizeEdgeTop: - case uiWindowResizeEdgeTopLeft: - case uiWindowResizeEdgeTopRight: - handleResizeTop(&frame, p->initialPoint, new); - break; - case uiWindowResizeEdgeBottom: - case uiWindowResizeEdgeBottomLeft: - case uiWindowResizeEdgeBottomRight: - handleResizeBottom(&frame, p->initialPoint, new); - break; - } - - // constrain - // TODO should we constrain against anything else as well? minMaxAutoLayoutSizes() already gives us nonnegative sizes, but... - if (frame.size.width < p->min.width) - frame.size.width = p->min.width; - if (frame.size.height < p->min.height) - frame.size.height = p->min.height; - // TODO > or >= ? - if (frame.size.width > p->max.width) - frame.size.width = p->max.width; - if (frame.size.height > p->max.height) - frame.size.height = p->max.height; - - [p->w setFrame:frame display:YES]; // and do reflect the new frame immediately -} - -// TODO do our events get fired with this? *should* they? -void doManualResize(NSWindow *w, NSEvent *initialEvent, uiWindowResizeEdge edge) -{ - __block struct onResizeDragParams rdp; - struct nextEventArgs nea; - BOOL (^handleEvent)(NSEvent *e); - __block BOOL done; - - rdp.w = w; - rdp.initialFrame = [rdp.w frame]; - rdp.initialPoint = makeIndependent([initialEvent locationInWindow], rdp.w); - rdp.edge = edge; - // TODO what happens if these change during the loop? - minMaxAutoLayoutSizes(rdp.w, &(rdp.min), &(rdp.max)); - - nea.mask = NSLeftMouseDraggedMask | NSLeftMouseUpMask; - nea.duration = [NSDate distantFuture]; - nea.mode = NSEventTrackingRunLoopMode; // nextEventMatchingMask: docs suggest using this for manual mouse tracking - nea.dequeue = YES; - handleEvent = ^(NSEvent *e) { - if ([e type] == NSLeftMouseUp) { - done = YES; - return YES; // do not send - } - onResizeDrag(&rdp, e); - return YES; // do not send - }; - done = NO; - while (mainStep(&nea, handleEvent)) - if (done) - break; -} diff --git a/deps/libui/libui_main.c b/deps/libui/libui_main.c deleted file mode 100644 index 8c54f05849..0000000000 --- a/deps/libui/libui_main.c +++ /dev/null @@ -1,543 +0,0 @@ -/* 2 september 2015 */ -#include -#include -#include "ui.h" -#include "../../verbosity.h" - -static int onClosing(uiWindow *w, void *data) -{ - uiQuit(); - return 1; -} - -static int onShouldQuit(void *data) -{ - uiWindow *mainwin = uiWindow(data); - - uiControlDestroy(uiControl(mainwin)); - return 1; -} - -static uiControl *makeBasicControlsPage(void) -{ - uiBox *vbox; - uiBox *hbox; - uiGroup *group; - uiForm *entryForm; - - vbox = uiNewVerticalBox(); - uiBoxSetPadded(vbox, 1); - - hbox = uiNewHorizontalBox(); - uiBoxSetPadded(hbox, 1); - uiBoxAppend(vbox, uiControl(hbox), 0); - - uiBoxAppend(hbox, - uiControl(uiNewButton("Button")), - 0); - uiBoxAppend(hbox, - uiControl(uiNewCheckbox("Checkbox")), - 0); - - uiBoxAppend(vbox, - uiControl(uiNewLabel("This is a label. Right now, labels can only span one line.")), - 0); - - uiBoxAppend(vbox, - uiControl(uiNewHorizontalSeparator()), - 0); - - group = uiNewGroup("Entries"); - uiGroupSetMargined(group, 1); - uiBoxAppend(vbox, uiControl(group), 1); - - entryForm = uiNewForm(); - uiFormSetPadded(entryForm, 1); - uiGroupSetChild(group, uiControl(entryForm)); - - uiFormAppend(entryForm, - "Entry", - uiControl(uiNewEntry()), - 0); - uiFormAppend(entryForm, - "Password Entry", - uiControl(uiNewPasswordEntry()), - 0); - uiFormAppend(entryForm, - "Search Entry", - uiControl(uiNewSearchEntry()), - 0); - uiFormAppend(entryForm, - "Multiline Entry", - uiControl(uiNewMultilineEntry()), - 1); - uiFormAppend(entryForm, - "Multiline Entry No Wrap", - uiControl(uiNewNonWrappingMultilineEntry()), - 1); - - return uiControl(vbox); -} - -// TODO make these not global -static uiSpinbox *spinbox; -static uiSlider *slider; -static uiProgressBar *pbar; - -static void onSpinboxChanged(uiSpinbox *s, void *data) -{ - uiSliderSetValue(slider, uiSpinboxValue(s)); - uiProgressBarSetValue(pbar, uiSpinboxValue(s)); -} - -static void onSliderChanged(uiSlider *s, void *data) -{ - uiSpinboxSetValue(spinbox, uiSliderValue(s)); - uiProgressBarSetValue(pbar, uiSliderValue(s)); -} - -static uiControl *makeNumbersPage() -{ - uiBox *hbox; - uiGroup *group; - uiBox *vbox; - uiProgressBar *ip; - uiCombobox *cbox; - uiEditableCombobox *ecbox; - uiRadioButtons *rb; - - hbox = uiNewHorizontalBox(); - uiBoxSetPadded(hbox, 1); - - group = uiNewGroup("Numbers"); - uiGroupSetMargined(group, 1); - uiBoxAppend(hbox, uiControl(group), 1); - - vbox = uiNewVerticalBox(); - uiBoxSetPadded(vbox, 1); - uiGroupSetChild(group, uiControl(vbox)); - - spinbox = uiNewSpinbox(0, 100); - slider = uiNewSlider(0, 100); - pbar = uiNewProgressBar(); - uiSpinboxOnChanged(spinbox, onSpinboxChanged, NULL); - uiSliderOnChanged(slider, onSliderChanged, NULL); - uiBoxAppend(vbox, uiControl(spinbox), 0); - uiBoxAppend(vbox, uiControl(slider), 0); - uiBoxAppend(vbox, uiControl(pbar), 0); - - ip = uiNewProgressBar(); - uiProgressBarSetValue(ip, -1); - uiBoxAppend(vbox, uiControl(ip), 0); - - group = uiNewGroup("Lists"); - uiGroupSetMargined(group, 1); - uiBoxAppend(hbox, uiControl(group), 1); - - vbox = uiNewVerticalBox(); - uiBoxSetPadded(vbox, 1); - uiGroupSetChild(group, uiControl(vbox)); - - cbox = uiNewCombobox(); - uiComboboxAppend(cbox, "Combobox Item 1"); - uiComboboxAppend(cbox, "Combobox Item 2"); - uiComboboxAppend(cbox, "Combobox Item 3"); - uiBoxAppend(vbox, uiControl(cbox), 0); - - ecbox = uiNewEditableCombobox(); - uiEditableComboboxAppend(ecbox, "Editable Item 1"); - uiEditableComboboxAppend(ecbox, "Editable Item 2"); - uiEditableComboboxAppend(ecbox, "Editable Item 3"); - uiBoxAppend(vbox, uiControl(ecbox), 0); - - rb = uiNewRadioButtons(); - uiRadioButtonsAppend(rb, "Radio Button 1"); - uiRadioButtonsAppend(rb, "Radio Button 2"); - uiRadioButtonsAppend(rb, "Radio Button 3"); - uiBoxAppend(vbox, uiControl(rb), 0); - - return uiControl(hbox); -} - -// TODO make this not global -static uiWindow *mainwin; - -static void onOpenFileClicked(uiButton *b, void *data) -{ - uiEntry *entry = uiEntry(data); - char *filename; - - filename = uiOpenFile(mainwin); - if (filename == NULL) { - uiEntrySetText(entry, "(cancelled)"); - return; - } - uiEntrySetText(entry, filename); - uiFreeText(filename); -} - -static void onSaveFileClicked(uiButton *b, void *data) -{ - uiEntry *entry = uiEntry(data); - char *filename; - - filename = uiSaveFile(mainwin); - if (filename == NULL) { - uiEntrySetText(entry, "(cancelled)"); - return; - } - uiEntrySetText(entry, filename); - uiFreeText(filename); -} - -static void onMsgBoxClicked(uiButton *b, void *data) -{ - uiMsgBox(mainwin, - "This is a normal message box.", - "More detailed information can be shown here."); -} - -static void onMsgBoxErrorClicked(uiButton *b, void *data) -{ - uiMsgBoxError(mainwin, - "This message box describes an error.", - "More detailed information can be shown here."); -} - -static uiControl *makeDataChoosersPage(void) -{ - uiBox *hbox; - uiBox *vbox; - uiGrid *grid; - uiButton *button; - uiEntry *entry; - uiGrid *msggrid; - - hbox = uiNewHorizontalBox(); - uiBoxSetPadded(hbox, 1); - - vbox = uiNewVerticalBox(); - uiBoxSetPadded(vbox, 1); - uiBoxAppend(hbox, uiControl(vbox), 0); - - uiBoxAppend(vbox, - uiControl(uiNewDatePicker()), - 0); - uiBoxAppend(vbox, - uiControl(uiNewTimePicker()), - 0); - uiBoxAppend(vbox, - uiControl(uiNewDateTimePicker()), - 0); - - uiBoxAppend(vbox, - uiControl(uiNewFontButton()), - 0); - uiBoxAppend(vbox, - uiControl(uiNewColorButton()), - 0); - - uiBoxAppend(hbox, - uiControl(uiNewVerticalSeparator()), - 0); - - vbox = uiNewVerticalBox(); - uiBoxSetPadded(vbox, 1); - uiBoxAppend(hbox, uiControl(vbox), 1); - - grid = uiNewGrid(); - uiGridSetPadded(grid, 1); - uiBoxAppend(vbox, uiControl(grid), 0); - - button = uiNewButton("Open File"); - entry = uiNewEntry(); - uiEntrySetReadOnly(entry, 1); - uiButtonOnClicked(button, onOpenFileClicked, entry); - uiGridAppend(grid, uiControl(button), - 0, 0, 1, 1, - 0, uiAlignFill, 0, uiAlignFill); - uiGridAppend(grid, uiControl(entry), - 1, 0, 1, 1, - 1, uiAlignFill, 0, uiAlignFill); - - button = uiNewButton("Save File"); - entry = uiNewEntry(); - uiEntrySetReadOnly(entry, 1); - uiButtonOnClicked(button, onSaveFileClicked, entry); - uiGridAppend(grid, uiControl(button), - 0, 1, 1, 1, - 0, uiAlignFill, 0, uiAlignFill); - uiGridAppend(grid, uiControl(entry), - 1, 1, 1, 1, - 1, uiAlignFill, 0, uiAlignFill); - - msggrid = uiNewGrid(); - uiGridSetPadded(msggrid, 1); - uiGridAppend(grid, uiControl(msggrid), - 0, 2, 2, 1, - 0, uiAlignCenter, 0, uiAlignStart); - - button = uiNewButton("Message Box"); - uiButtonOnClicked(button, onMsgBoxClicked, NULL); - uiGridAppend(msggrid, uiControl(button), - 0, 0, 1, 1, - 0, uiAlignFill, 0, uiAlignFill); - button = uiNewButton("Error Box"); - uiButtonOnClicked(button, onMsgBoxErrorClicked, NULL); - uiGridAppend(msggrid, uiControl(button), - 1, 0, 1, 1, - 0, uiAlignFill, 0, uiAlignFill); - - return uiControl(hbox); -} - -int libui_main(void) -{ - uiInitOptions options; - const char *err; - uiTab *tab; - - memset(&options, 0, sizeof (uiInitOptions)); - err = uiInit(&options); - if (err != NULL) - { - RARCH_ERR("Failed to initialize uiInit\n"); - fprintf(stderr, "error initializing libui: %s", err); - uiFreeInitError(err); - return 1; - } - - mainwin = uiNewWindow("libui Control Gallery", 640, 480, 1); - uiWindowOnClosing(mainwin, onClosing, NULL); - uiOnShouldQuit(onShouldQuit, mainwin); - - tab = uiNewTab(); - uiWindowSetChild(mainwin, uiControl(tab)); - uiWindowSetMargined(mainwin, 1); - - uiTabAppend(tab, "Basic Controls", makeBasicControlsPage()); - uiTabSetMargined(tab, 0, 1); - - uiTabAppend(tab, "Numbers and Lists", makeNumbersPage()); - uiTabSetMargined(tab, 1, 1); - - uiTabAppend(tab, "Data Choosers", makeDataChoosersPage()); - uiTabSetMargined(tab, 2, 1); - - uiControlShow(uiControl(mainwin)); - uiMain(); - return 0; -} - -#if 0 - -static void openClicked(uiMenuItem *item, uiWindow *w, void *data) -{ - char *filename; - - filename = uiOpenFile(mainwin); - if (filename == NULL) { - uiMsgBoxError(mainwin, "No file selected", "Don't be alarmed!"); - return; - } - uiMsgBox(mainwin, "File selected", filename); - uiFreeText(filename); -} - -static void saveClicked(uiMenuItem *item, uiWindow *w, void *data) -{ - char *filename; - - filename = uiSaveFile(mainwin); - if (filename == NULL) { - uiMsgBoxError(mainwin, "No file selected", "Don't be alarmed!"); - return; - } - uiMsgBox(mainwin, "File selected (don't worry, it's still there)", filename); - uiFreeText(filename); -} - -static uiSpinbox *spinbox; -static uiSlider *slider; -static uiProgressBar *progressbar; - -static void update(int value) -{ - uiSpinboxSetValue(spinbox, value); - uiSliderSetValue(slider, value); - uiProgressBarSetValue(progressbar, value); -} - -static void onSpinboxChanged(uiSpinbox *s, void *data) -{ - update(uiSpinboxValue(spinbox)); -} - -static void onSliderChanged(uiSlider *s, void *data) -{ - update(uiSliderValue(slider)); -} - -int main(void) -{ - uiInitOptions o; - const char *err; - uiMenu *menu; - uiMenuItem *item; - uiBox *box; - uiBox *hbox; - uiGroup *group; - uiBox *inner; - uiBox *inner2; - uiEntry *entry; - uiCombobox *cbox; - uiEditableCombobox *ecbox; - uiRadioButtons *rb; - uiTab *tab; - - memset(&o, 0, sizeof (uiInitOptions)); - err = uiInit(&o); - if (err != NULL) { - fprintf(stderr, "error initializing ui: %s\n", err); - uiFreeInitError(err); - return 1; - } - - menu = uiNewMenu("File"); - item = uiMenuAppendItem(menu, "Open"); - uiMenuItemOnClicked(item, openClicked, NULL); - item = uiMenuAppendItem(menu, "Save"); - uiMenuItemOnClicked(item, saveClicked, NULL); - item = uiMenuAppendQuitItem(menu); - uiOnShouldQuit(shouldQuit, NULL); - - menu = uiNewMenu("Edit"); - item = uiMenuAppendCheckItem(menu, "Checkable Item"); - uiMenuAppendSeparator(menu); - item = uiMenuAppendItem(menu, "Disabled Item"); - uiMenuItemDisable(item); - item = uiMenuAppendPreferencesItem(menu); - - menu = uiNewMenu("Help"); - item = uiMenuAppendItem(menu, "Help"); - item = uiMenuAppendAboutItem(menu); - - mainwin = uiNewWindow("libui Control Gallery", 640, 480, 1); - uiWindowSetMargined(mainwin, 1); - uiWindowOnClosing(mainwin, onClosing, NULL); - - box = uiNewVerticalBox(); - uiBoxSetPadded(box, 1); - uiWindowSetChild(mainwin, uiControl(box)); - - hbox = uiNewHorizontalBox(); - uiBoxSetPadded(hbox, 1); - uiBoxAppend(box, uiControl(hbox), 1); - - group = uiNewGroup("Basic Controls"); - uiGroupSetMargined(group, 1); - uiBoxAppend(hbox, uiControl(group), 0); - - inner = uiNewVerticalBox(); - uiBoxSetPadded(inner, 1); - uiGroupSetChild(group, uiControl(inner)); - - uiBoxAppend(inner, - uiControl(uiNewButton("Button")), - 0); - uiBoxAppend(inner, - uiControl(uiNewCheckbox("Checkbox")), - 0); - entry = uiNewEntry(); - uiEntrySetText(entry, "Entry"); - uiBoxAppend(inner, - uiControl(entry), - 0); - uiBoxAppend(inner, - uiControl(uiNewLabel("Label")), - 0); - - uiBoxAppend(inner, - uiControl(uiNewHorizontalSeparator()), - 0); - - uiBoxAppend(inner, - uiControl(uiNewDatePicker()), - 0); - uiBoxAppend(inner, - uiControl(uiNewTimePicker()), - 0); - uiBoxAppend(inner, - uiControl(uiNewDateTimePicker()), - 0); - - uiBoxAppend(inner, - uiControl(uiNewFontButton()), - 0); - - uiBoxAppend(inner, - uiControl(uiNewColorButton()), - 0); - - inner2 = uiNewVerticalBox(); - uiBoxSetPadded(inner2, 1); - uiBoxAppend(hbox, uiControl(inner2), 1); - - group = uiNewGroup("Numbers"); - uiGroupSetMargined(group, 1); - uiBoxAppend(inner2, uiControl(group), 0); - - inner = uiNewVerticalBox(); - uiBoxSetPadded(inner, 1); - uiGroupSetChild(group, uiControl(inner)); - - spinbox = uiNewSpinbox(0, 100); - uiSpinboxOnChanged(spinbox, onSpinboxChanged, NULL); - uiBoxAppend(inner, uiControl(spinbox), 0); - - slider = uiNewSlider(0, 100); - uiSliderOnChanged(slider, onSliderChanged, NULL); - uiBoxAppend(inner, uiControl(slider), 0); - - progressbar = uiNewProgressBar(); - uiBoxAppend(inner, uiControl(progressbar), 0); - - group = uiNewGroup("Lists"); - uiGroupSetMargined(group, 1); - uiBoxAppend(inner2, uiControl(group), 0); - - inner = uiNewVerticalBox(); - uiBoxSetPadded(inner, 1); - uiGroupSetChild(group, uiControl(inner)); - - cbox = uiNewCombobox(); - uiComboboxAppend(cbox, "Combobox Item 1"); - uiComboboxAppend(cbox, "Combobox Item 2"); - uiComboboxAppend(cbox, "Combobox Item 3"); - uiBoxAppend(inner, uiControl(cbox), 0); - - ecbox = uiNewEditableCombobox(); - uiEditableComboboxAppend(ecbox, "Editable Item 1"); - uiEditableComboboxAppend(ecbox, "Editable Item 2"); - uiEditableComboboxAppend(ecbox, "Editable Item 3"); - uiBoxAppend(inner, uiControl(ecbox), 0); - - rb = uiNewRadioButtons(); - uiRadioButtonsAppend(rb, "Radio Button 1"); - uiRadioButtonsAppend(rb, "Radio Button 2"); - uiRadioButtonsAppend(rb, "Radio Button 3"); - uiBoxAppend(inner, uiControl(rb), 1); - - tab = uiNewTab(); - uiTabAppend(tab, "Page 1", uiControl(uiNewHorizontalBox())); - uiTabAppend(tab, "Page 2", uiControl(uiNewHorizontalBox())); - uiTabAppend(tab, "Page 3", uiControl(uiNewHorizontalBox())); - uiBoxAppend(inner2, uiControl(tab), 1); - - uiControlShow(uiControl(mainwin)); - uiMain(); - uiUninit(); - return 0; -} - -#endif diff --git a/deps/libui/ui.h b/deps/libui/ui.h deleted file mode 100644 index 5a2069e8a7..0000000000 --- a/deps/libui/ui.h +++ /dev/null @@ -1,691 +0,0 @@ -// 6 april 2015 - -// TODO add a uiVerifyControlType() function that can be used by control implementations to verify controls - -#ifndef __LIBUI_UI_H__ -#define __LIBUI_UI_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// this macro is generated by cmake -#ifdef libui_EXPORTS -#ifdef _WIN32 -#define _UI_EXTERN __declspec(dllexport) extern -#else -#define _UI_EXTERN __attribute__((visibility("default"))) extern -#endif -#else -// TODO add __declspec(dllimport) on windows, but only if not static -#define _UI_EXTERN extern -#endif - -// C++ is really really really really really really dumb about enums, so screw that and just make them anonymous -// This has the advantage of being ABI-able should we ever need an ABI... -#define _UI_ENUM(s) typedef unsigned int s; enum - -// This constant is provided because M_PI is nonstandard. -// This comes from Go's math.Pi, which in turn comes from http://oeis.org/A000796. -#define uiPi 3.14159265358979323846264338327950288419716939937510582097494459 - -// TODO uiBool? - -typedef struct uiInitOptions uiInitOptions; - -struct uiInitOptions { - size_t Size; -}; - -_UI_EXTERN const char *uiInit(uiInitOptions *options); -_UI_EXTERN void uiUninit(void); -_UI_EXTERN void uiFreeInitError(const char *err); - -_UI_EXTERN void uiMain(void); -_UI_EXTERN void uiMainSteps(void); -_UI_EXTERN int uiMainStep(int wait); -_UI_EXTERN void uiQuit(void); - -_UI_EXTERN void uiQueueMain(void (*f)(void *data), void *data); - -_UI_EXTERN void uiOnShouldQuit(int (*f)(void *data), void *data); - -_UI_EXTERN void uiFreeText(char *text); - -typedef struct uiControl uiControl; - -struct uiControl { - uint32_t Signature; - uint32_t OSSignature; - uint32_t TypeSignature; - void (*Destroy)(uiControl *); - uintptr_t (*Handle)(uiControl *); - uiControl *(*Parent)(uiControl *); - void (*SetParent)(uiControl *, uiControl *); - int (*Toplevel)(uiControl *); - int (*Visible)(uiControl *); - void (*Show)(uiControl *); - void (*Hide)(uiControl *); - int (*Enabled)(uiControl *); - void (*Enable)(uiControl *); - void (*Disable)(uiControl *); -}; -// TOOD add argument names to all arguments -#define uiControl(this) ((uiControl *) (this)) -_UI_EXTERN void uiControlDestroy(uiControl *); -_UI_EXTERN uintptr_t uiControlHandle(uiControl *); -_UI_EXTERN uiControl *uiControlParent(uiControl *); -_UI_EXTERN void uiControlSetParent(uiControl *, uiControl *); -_UI_EXTERN int uiControlToplevel(uiControl *); -_UI_EXTERN int uiControlVisible(uiControl *); -_UI_EXTERN void uiControlShow(uiControl *); -_UI_EXTERN void uiControlHide(uiControl *); -_UI_EXTERN int uiControlEnabled(uiControl *); -_UI_EXTERN void uiControlEnable(uiControl *); -_UI_EXTERN void uiControlDisable(uiControl *); - -_UI_EXTERN uiControl *uiAllocControl(size_t n, uint32_t OSsig, uint32_t typesig, const char *typenamestr); -_UI_EXTERN void uiFreeControl(uiControl *); - -// TODO make sure all controls have these -_UI_EXTERN void uiControlVerifySetParent(uiControl *, uiControl *); -_UI_EXTERN int uiControlEnabledToUser(uiControl *); - -_UI_EXTERN void uiUserBugCannotSetParentOnToplevel(const char *type); - -typedef struct uiWindow uiWindow; -#define uiWindow(this) ((uiWindow *) (this)) -_UI_EXTERN char *uiWindowTitle(uiWindow *w); -_UI_EXTERN void uiWindowSetTitle(uiWindow *w, const char *title); -_UI_EXTERN void uiWindowContentSize(uiWindow *w, int *width, int *height); -_UI_EXTERN void uiWindowSetContentSize(uiWindow *w, int width, int height); -_UI_EXTERN int uiWindowFullscreen(uiWindow *w); -_UI_EXTERN void uiWindowSetFullscreen(uiWindow *w, int fullscreen); -_UI_EXTERN void uiWindowOnContentSizeChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data); -_UI_EXTERN void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *w, void *data), void *data); -_UI_EXTERN int uiWindowBorderless(uiWindow *w); -_UI_EXTERN void uiWindowSetBorderless(uiWindow *w, int borderless); -_UI_EXTERN void uiWindowSetChild(uiWindow *w, uiControl *child); -_UI_EXTERN int uiWindowMargined(uiWindow *w); -_UI_EXTERN void uiWindowSetMargined(uiWindow *w, int margined); -_UI_EXTERN uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar); - -typedef struct uiButton uiButton; -#define uiButton(this) ((uiButton *) (this)) -_UI_EXTERN char *uiButtonText(uiButton *b); -_UI_EXTERN void uiButtonSetText(uiButton *b, const char *text); -_UI_EXTERN void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *b, void *data), void *data); -_UI_EXTERN uiButton *uiNewButton(const char *text); - -typedef struct uiBox uiBox; -#define uiBox(this) ((uiBox *) (this)) -_UI_EXTERN void uiBoxAppend(uiBox *b, uiControl *child, int stretchy); -_UI_EXTERN void uiBoxDelete(uiBox *b, int index); -_UI_EXTERN int uiBoxPadded(uiBox *b); -_UI_EXTERN void uiBoxSetPadded(uiBox *b, int padded); -_UI_EXTERN uiBox *uiNewHorizontalBox(void); -_UI_EXTERN uiBox *uiNewVerticalBox(void); - -typedef struct uiCheckbox uiCheckbox; -#define uiCheckbox(this) ((uiCheckbox *) (this)) -_UI_EXTERN char *uiCheckboxText(uiCheckbox *c); -_UI_EXTERN void uiCheckboxSetText(uiCheckbox *c, const char *text); -_UI_EXTERN void uiCheckboxOnToggled(uiCheckbox *c, void (*f)(uiCheckbox *c, void *data), void *data); -_UI_EXTERN int uiCheckboxChecked(uiCheckbox *c); -_UI_EXTERN void uiCheckboxSetChecked(uiCheckbox *c, int checked); -_UI_EXTERN uiCheckbox *uiNewCheckbox(const char *text); - -typedef struct uiEntry uiEntry; -#define uiEntry(this) ((uiEntry *) (this)) -_UI_EXTERN char *uiEntryText(uiEntry *e); -_UI_EXTERN void uiEntrySetText(uiEntry *e, const char *text); -_UI_EXTERN void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *e, void *data), void *data); -_UI_EXTERN int uiEntryReadOnly(uiEntry *e); -_UI_EXTERN void uiEntrySetReadOnly(uiEntry *e, int readonly); -_UI_EXTERN uiEntry *uiNewEntry(void); -_UI_EXTERN uiEntry *uiNewPasswordEntry(void); -_UI_EXTERN uiEntry *uiNewSearchEntry(void); - -typedef struct uiLabel uiLabel; -#define uiLabel(this) ((uiLabel *) (this)) -_UI_EXTERN char *uiLabelText(uiLabel *l); -_UI_EXTERN void uiLabelSetText(uiLabel *l, const char *text); -_UI_EXTERN uiLabel *uiNewLabel(const char *text); - -typedef struct uiTab uiTab; -#define uiTab(this) ((uiTab *) (this)) -_UI_EXTERN void uiTabAppend(uiTab *t, const char *name, uiControl *c); -_UI_EXTERN void uiTabInsertAt(uiTab *t, const char *name, int before, uiControl *c); -_UI_EXTERN void uiTabDelete(uiTab *t, int index); -_UI_EXTERN int uiTabNumPages(uiTab *t); -_UI_EXTERN int uiTabMargined(uiTab *t, int page); -_UI_EXTERN void uiTabSetMargined(uiTab *t, int page, int margined); -_UI_EXTERN uiTab *uiNewTab(void); - -typedef struct uiGroup uiGroup; -#define uiGroup(this) ((uiGroup *) (this)) -_UI_EXTERN char *uiGroupTitle(uiGroup *g); -_UI_EXTERN void uiGroupSetTitle(uiGroup *g, const char *title); -_UI_EXTERN void uiGroupSetChild(uiGroup *g, uiControl *c); -_UI_EXTERN int uiGroupMargined(uiGroup *g); -_UI_EXTERN void uiGroupSetMargined(uiGroup *g, int margined); -_UI_EXTERN uiGroup *uiNewGroup(const char *title); - -// spinbox/slider rules: -// setting value outside of range will automatically clamp -// initial value is minimum -// complaint if min >= max? - -typedef struct uiSpinbox uiSpinbox; -#define uiSpinbox(this) ((uiSpinbox *) (this)) -_UI_EXTERN int uiSpinboxValue(uiSpinbox *s); -_UI_EXTERN void uiSpinboxSetValue(uiSpinbox *s, int value); -_UI_EXTERN void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *s, void *data), void *data); -_UI_EXTERN uiSpinbox *uiNewSpinbox(int min, int max); - -typedef struct uiSlider uiSlider; -#define uiSlider(this) ((uiSlider *) (this)) -_UI_EXTERN int uiSliderValue(uiSlider *s); -_UI_EXTERN void uiSliderSetValue(uiSlider *s, int value); -_UI_EXTERN void uiSliderOnChanged(uiSlider *s, void (*f)(uiSlider *s, void *data), void *data); -_UI_EXTERN uiSlider *uiNewSlider(int min, int max); - -typedef struct uiProgressBar uiProgressBar; -#define uiProgressBar(this) ((uiProgressBar *) (this)) -_UI_EXTERN int uiProgressBarValue(uiProgressBar *p); -_UI_EXTERN void uiProgressBarSetValue(uiProgressBar *p, int n); -_UI_EXTERN uiProgressBar *uiNewProgressBar(void); - -typedef struct uiSeparator uiSeparator; -#define uiSeparator(this) ((uiSeparator *) (this)) -_UI_EXTERN uiSeparator *uiNewHorizontalSeparator(void); -_UI_EXTERN uiSeparator *uiNewVerticalSeparator(void); - -typedef struct uiCombobox uiCombobox; -#define uiCombobox(this) ((uiCombobox *) (this)) -_UI_EXTERN void uiComboboxAppend(uiCombobox *c, const char *text); -_UI_EXTERN int uiComboboxSelected(uiCombobox *c); -_UI_EXTERN void uiComboboxSetSelected(uiCombobox *c, int n); -_UI_EXTERN void uiComboboxOnSelected(uiCombobox *c, void (*f)(uiCombobox *c, void *data), void *data); -_UI_EXTERN uiCombobox *uiNewCombobox(void); - -typedef struct uiEditableCombobox uiEditableCombobox; -#define uiEditableCombobox(this) ((uiEditableCombobox *) (this)) -_UI_EXTERN void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text); -_UI_EXTERN char *uiEditableComboboxText(uiEditableCombobox *c); -_UI_EXTERN void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text); -// TODO what do we call a function that sets the currently selected item and fills the text field with it? editable comboboxes have no consistent concept of selected item -_UI_EXTERN void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data); -_UI_EXTERN uiEditableCombobox *uiNewEditableCombobox(void); - -typedef struct uiRadioButtons uiRadioButtons; -#define uiRadioButtons(this) ((uiRadioButtons *) (this)) -_UI_EXTERN void uiRadioButtonsAppend(uiRadioButtons *r, const char *text); -_UI_EXTERN int uiRadioButtonsSelected(uiRadioButtons *r); -_UI_EXTERN void uiRadioButtonsSetSelected(uiRadioButtons *r, int n); -_UI_EXTERN void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data); -_UI_EXTERN uiRadioButtons *uiNewRadioButtons(void); - -typedef struct uiDateTimePicker uiDateTimePicker; -#define uiDateTimePicker(this) ((uiDateTimePicker *) (this)) -_UI_EXTERN uiDateTimePicker *uiNewDateTimePicker(void); -_UI_EXTERN uiDateTimePicker *uiNewDatePicker(void); -_UI_EXTERN uiDateTimePicker *uiNewTimePicker(void); - -// TODO provide a facility for entering tab stops? -typedef struct uiMultilineEntry uiMultilineEntry; -#define uiMultilineEntry(this) ((uiMultilineEntry *) (this)) -_UI_EXTERN char *uiMultilineEntryText(uiMultilineEntry *e); -_UI_EXTERN void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text); -_UI_EXTERN void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text); -_UI_EXTERN void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *e, void *data), void *data); -_UI_EXTERN int uiMultilineEntryReadOnly(uiMultilineEntry *e); -_UI_EXTERN void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly); -_UI_EXTERN uiMultilineEntry *uiNewMultilineEntry(void); -_UI_EXTERN uiMultilineEntry *uiNewNonWrappingMultilineEntry(void); - -typedef struct uiMenuItem uiMenuItem; -#define uiMenuItem(this) ((uiMenuItem *) (this)) -_UI_EXTERN void uiMenuItemEnable(uiMenuItem *m); -_UI_EXTERN void uiMenuItemDisable(uiMenuItem *m); -_UI_EXTERN void uiMenuItemOnClicked(uiMenuItem *m, void (*f)(uiMenuItem *sender, uiWindow *window, void *data), void *data); -_UI_EXTERN int uiMenuItemChecked(uiMenuItem *m); -_UI_EXTERN void uiMenuItemSetChecked(uiMenuItem *m, int checked); - -typedef struct uiMenu uiMenu; -#define uiMenu(this) ((uiMenu *) (this)) -_UI_EXTERN uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name); -_UI_EXTERN uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name); -_UI_EXTERN uiMenuItem *uiMenuAppendQuitItem(uiMenu *m); -_UI_EXTERN uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m); -_UI_EXTERN uiMenuItem *uiMenuAppendAboutItem(uiMenu *m); -_UI_EXTERN void uiMenuAppendSeparator(uiMenu *m); -_UI_EXTERN uiMenu *uiNewMenu(const char *name); - -_UI_EXTERN char *uiOpenFile(uiWindow *parent); -_UI_EXTERN char *uiSaveFile(uiWindow *parent); -_UI_EXTERN void uiMsgBox(uiWindow *parent, const char *title, const char *description); -_UI_EXTERN void uiMsgBoxError(uiWindow *parent, const char *title, const char *description); - -typedef struct uiArea uiArea; -typedef struct uiAreaHandler uiAreaHandler; -typedef struct uiAreaDrawParams uiAreaDrawParams; -typedef struct uiAreaMouseEvent uiAreaMouseEvent; -typedef struct uiAreaKeyEvent uiAreaKeyEvent; - -typedef struct uiDrawContext uiDrawContext; - -struct uiAreaHandler { - void (*Draw)(uiAreaHandler *, uiArea *, uiAreaDrawParams *); - // TODO document that resizes cause a full redraw for non-scrolling areas; implementation-defined for scrolling areas - void (*MouseEvent)(uiAreaHandler *, uiArea *, uiAreaMouseEvent *); - // TODO document that on first show if the mouse is already in the uiArea then one gets sent with left=0 - // TODO what about when the area is hidden and then shown again? - void (*MouseCrossed)(uiAreaHandler *, uiArea *, int left); - void (*DragBroken)(uiAreaHandler *, uiArea *); - int (*KeyEvent)(uiAreaHandler *, uiArea *, uiAreaKeyEvent *); -}; - -// TODO RTL layouts? -// TODO reconcile edge and corner naming -_UI_ENUM(uiWindowResizeEdge) { - uiWindowResizeEdgeLeft, - uiWindowResizeEdgeTop, - uiWindowResizeEdgeRight, - uiWindowResizeEdgeBottom, - uiWindowResizeEdgeTopLeft, - uiWindowResizeEdgeTopRight, - uiWindowResizeEdgeBottomLeft, - uiWindowResizeEdgeBottomRight, - // TODO have one for keyboard resizes? - // TODO GDK doesn't seem to have any others, including for keyboards... - // TODO way to bring up the system menu instead? -}; - -#define uiArea(this) ((uiArea *) (this)) -// TODO give a better name -// TODO document the types of width and height -_UI_EXTERN void uiAreaSetSize(uiArea *a, int width, int height); -// TODO uiAreaQueueRedraw() -_UI_EXTERN void uiAreaQueueRedrawAll(uiArea *a); -_UI_EXTERN void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height); -// TODO document these can only be called within Mouse() handlers -// TODO should these be allowed on scrolling areas? -// TODO decide which mouse events should be accepted; Down is the only one guaranteed to work right now -// TODO what happens to events after calling this up to and including the next mouse up? -// TODO release capture? -_UI_EXTERN void uiAreaBeginUserWindowMove(uiArea *a); -_UI_EXTERN void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge); -_UI_EXTERN uiArea *uiNewArea(uiAreaHandler *ah); -_UI_EXTERN uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height); - -struct uiAreaDrawParams { - uiDrawContext *Context; - - // TODO document that this is only defined for nonscrolling areas - double AreaWidth; - double AreaHeight; - - double ClipX; - double ClipY; - double ClipWidth; - double ClipHeight; -}; - -typedef struct uiDrawPath uiDrawPath; -typedef struct uiDrawBrush uiDrawBrush; -typedef struct uiDrawStrokeParams uiDrawStrokeParams; -typedef struct uiDrawMatrix uiDrawMatrix; - -typedef struct uiDrawBrushGradientStop uiDrawBrushGradientStop; - -_UI_ENUM(uiDrawBrushType) { - uiDrawBrushTypeSolid, - uiDrawBrushTypeLinearGradient, - uiDrawBrushTypeRadialGradient, - uiDrawBrushTypeImage, -}; - -_UI_ENUM(uiDrawLineCap) { - uiDrawLineCapFlat, - uiDrawLineCapRound, - uiDrawLineCapSquare, -}; - -_UI_ENUM(uiDrawLineJoin) { - uiDrawLineJoinMiter, - uiDrawLineJoinRound, - uiDrawLineJoinBevel, -}; - -// this is the default for botoh cairo and Direct2D (in the latter case, from the C++ helper functions) -// Core Graphics doesn't explicitly specify a default, but NSBezierPath allows you to choose one, and this is the initial value -// so we're good to use it too! -#define uiDrawDefaultMiterLimit 10.0 - -_UI_ENUM(uiDrawFillMode) { - uiDrawFillModeWinding, - uiDrawFillModeAlternate, -}; - -struct uiDrawMatrix { - double M11; - double M12; - double M21; - double M22; - double M31; - double M32; -}; - -struct uiDrawBrush { - uiDrawBrushType Type; - - // solid brushes - double R; - double G; - double B; - double A; - - // gradient brushes - double X0; // linear: start X, radial: start X - double Y0; // linear: start Y, radial: start Y - double X1; // linear: end X, radial: outer circle center X - double Y1; // linear: end Y, radial: outer circle center Y - double OuterRadius; // radial gradients only - uiDrawBrushGradientStop *Stops; - size_t NumStops; - // TODO extend mode - // cairo: none, repeat, reflect, pad; no individual control - // Direct2D: repeat, reflect, pad; no individual control - // Core Graphics: none, pad; before and after individually - // TODO cairo documentation is inconsistent about pad - - // TODO images - - // TODO transforms -}; - -struct uiDrawBrushGradientStop { - double Pos; - double R; - double G; - double B; - double A; -}; - -struct uiDrawStrokeParams { - uiDrawLineCap Cap; - uiDrawLineJoin Join; - // TODO what if this is 0? on windows there will be a crash with dashing - double Thickness; - double MiterLimit; - double *Dashes; - // TOOD what if this is 1 on Direct2D? - // TODO what if a dash is 0 on Cairo or Quartz? - size_t NumDashes; - double DashPhase; -}; - -_UI_EXTERN uiDrawPath *uiDrawNewPath(uiDrawFillMode fillMode); -_UI_EXTERN void uiDrawFreePath(uiDrawPath *p); - -_UI_EXTERN void uiDrawPathNewFigure(uiDrawPath *p, double x, double y); -_UI_EXTERN void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative); -_UI_EXTERN void uiDrawPathLineTo(uiDrawPath *p, double x, double y); -// notes: angles are both relative to 0 and go counterclockwise -// TODO is the initial line segment on cairo and OS X a proper join? -// TODO what if sweep < 0? -_UI_EXTERN void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative); -_UI_EXTERN void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY); -// TODO quadratic bezier -_UI_EXTERN void uiDrawPathCloseFigure(uiDrawPath *p); - -// TODO effect of these when a figure is already started -_UI_EXTERN void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height); - -_UI_EXTERN void uiDrawPathEnd(uiDrawPath *p); - -_UI_EXTERN void uiDrawStroke(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b, uiDrawStrokeParams *p); -_UI_EXTERN void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b); - -// TODO primitives: -// - rounded rectangles -// - elliptical arcs -// - quadratic bezier curves - -_UI_EXTERN void uiDrawMatrixSetIdentity(uiDrawMatrix *m); -_UI_EXTERN void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y); -_UI_EXTERN void uiDrawMatrixScale(uiDrawMatrix *m, double xCenter, double yCenter, double x, double y); -_UI_EXTERN void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount); -_UI_EXTERN void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount); -_UI_EXTERN void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src); -_UI_EXTERN int uiDrawMatrixInvertible(uiDrawMatrix *m); -_UI_EXTERN int uiDrawMatrixInvert(uiDrawMatrix *m); -_UI_EXTERN void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y); -_UI_EXTERN void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y); - -_UI_EXTERN void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m); - -// TODO add a uiDrawPathStrokeToFill() or something like that -_UI_EXTERN void uiDrawClip(uiDrawContext *c, uiDrawPath *path); - -_UI_EXTERN void uiDrawSave(uiDrawContext *c); -_UI_EXTERN void uiDrawRestore(uiDrawContext *c); - -// TODO manage the use of Text, Font, and TextFont, and of the uiDrawText prefix in general - -///// TODO reconsider this -typedef struct uiDrawFontFamilies uiDrawFontFamilies; - -_UI_EXTERN uiDrawFontFamilies *uiDrawListFontFamilies(void); -_UI_EXTERN int uiDrawFontFamiliesNumFamilies(uiDrawFontFamilies *ff); -_UI_EXTERN char *uiDrawFontFamiliesFamily(uiDrawFontFamilies *ff, int n); -_UI_EXTERN void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff); -///// END TODO - -typedef struct uiDrawTextLayout uiDrawTextLayout; -typedef struct uiDrawTextFont uiDrawTextFont; -typedef struct uiDrawTextFontDescriptor uiDrawTextFontDescriptor; -typedef struct uiDrawTextFontMetrics uiDrawTextFontMetrics; - -_UI_ENUM(uiDrawTextWeight) { - uiDrawTextWeightThin, - uiDrawTextWeightUltraLight, - uiDrawTextWeightLight, - uiDrawTextWeightBook, - uiDrawTextWeightNormal, - uiDrawTextWeightMedium, - uiDrawTextWeightSemiBold, - uiDrawTextWeightBold, - uiDrawTextWeightUltraBold, - uiDrawTextWeightHeavy, - uiDrawTextWeightUltraHeavy, -}; - -_UI_ENUM(uiDrawTextItalic) { - uiDrawTextItalicNormal, - uiDrawTextItalicOblique, - uiDrawTextItalicItalic, -}; - -_UI_ENUM(uiDrawTextStretch) { - uiDrawTextStretchUltraCondensed, - uiDrawTextStretchExtraCondensed, - uiDrawTextStretchCondensed, - uiDrawTextStretchSemiCondensed, - uiDrawTextStretchNormal, - uiDrawTextStretchSemiExpanded, - uiDrawTextStretchExpanded, - uiDrawTextStretchExtraExpanded, - uiDrawTextStretchUltraExpanded, -}; - -struct uiDrawTextFontDescriptor { - const char *Family; - double Size; - uiDrawTextWeight Weight; - uiDrawTextItalic Italic; - uiDrawTextStretch Stretch; -}; - -struct uiDrawTextFontMetrics { - double Ascent; - double Descent; - double Leading; - // TODO do these two mean the same across all platforms? - double UnderlinePos; - double UnderlineThickness; -}; - -_UI_EXTERN uiDrawTextFont *uiDrawLoadClosestFont(const uiDrawTextFontDescriptor *desc); -_UI_EXTERN void uiDrawFreeTextFont(uiDrawTextFont *font); -_UI_EXTERN uintptr_t uiDrawTextFontHandle(uiDrawTextFont *font); -_UI_EXTERN void uiDrawTextFontDescribe(uiDrawTextFont *font, uiDrawTextFontDescriptor *desc); -// TODO make copy with given attributes methods? -// TODO yuck this name -_UI_EXTERN void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metrics); - -// TODO initial line spacing? and what about leading? -_UI_EXTERN uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultFont, double width); -_UI_EXTERN void uiDrawFreeTextLayout(uiDrawTextLayout *layout); -// TODO get width -_UI_EXTERN void uiDrawTextLayoutSetWidth(uiDrawTextLayout *layout, double width); -_UI_EXTERN void uiDrawTextLayoutExtents(uiDrawTextLayout *layout, double *width, double *height); - -// and the attributes that you can set on a text layout -_UI_EXTERN void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endChar, double r, double g, double b, double a); - -_UI_EXTERN void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout); - -_UI_ENUM(uiModifiers) { - uiModifierCtrl = 1 << 0, - uiModifierAlt = 1 << 1, - uiModifierShift = 1 << 2, - uiModifierSuper = 1 << 3, -}; - -// TODO document drag captures -struct uiAreaMouseEvent { - // TODO document what these mean for scrolling areas - double X; - double Y; - - // TODO see draw above - double AreaWidth; - double AreaHeight; - - int Down; - int Up; - - int Count; - - uiModifiers Modifiers; - - uint64_t Held1To64; -}; - -_UI_ENUM(uiExtKey) { - uiExtKeyEscape = 1, - uiExtKeyInsert, // equivalent to "Help" on Apple keyboards - uiExtKeyDelete, - uiExtKeyHome, - uiExtKeyEnd, - uiExtKeyPageUp, - uiExtKeyPageDown, - uiExtKeyUp, - uiExtKeyDown, - uiExtKeyLeft, - uiExtKeyRight, - uiExtKeyF1, // F1..F12 are guaranteed to be consecutive - uiExtKeyF2, - uiExtKeyF3, - uiExtKeyF4, - uiExtKeyF5, - uiExtKeyF6, - uiExtKeyF7, - uiExtKeyF8, - uiExtKeyF9, - uiExtKeyF10, - uiExtKeyF11, - uiExtKeyF12, - uiExtKeyN0, // numpad keys; independent of Num Lock state - uiExtKeyN1, // N0..N9 are guaranteed to be consecutive - uiExtKeyN2, - uiExtKeyN3, - uiExtKeyN4, - uiExtKeyN5, - uiExtKeyN6, - uiExtKeyN7, - uiExtKeyN8, - uiExtKeyN9, - uiExtKeyNDot, - uiExtKeyNEnter, - uiExtKeyNAdd, - uiExtKeyNSubtract, - uiExtKeyNMultiply, - uiExtKeyNDivide, -}; - -struct uiAreaKeyEvent { - char Key; - uiExtKey ExtKey; - uiModifiers Modifier; - - uiModifiers Modifiers; - - int Up; -}; - -typedef struct uiFontButton uiFontButton; -#define uiFontButton(this) ((uiFontButton *) (this)) -// TODO document this returns a new font -_UI_EXTERN uiDrawTextFont *uiFontButtonFont(uiFontButton *b); -// TOOD SetFont, mechanics -_UI_EXTERN void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data); -_UI_EXTERN uiFontButton *uiNewFontButton(void); - -typedef struct uiColorButton uiColorButton; -#define uiColorButton(this) ((uiColorButton *) (this)) -_UI_EXTERN void uiColorButtonColor(uiColorButton *b, double *r, double *g, double *bl, double *a); -_UI_EXTERN void uiColorButtonSetColor(uiColorButton *b, double r, double g, double bl, double a); -_UI_EXTERN void uiColorButtonOnChanged(uiColorButton *b, void (*f)(uiColorButton *, void *), void *data); -_UI_EXTERN uiColorButton *uiNewColorButton(void); - -typedef struct uiForm uiForm; -#define uiForm(this) ((uiForm *) (this)) -_UI_EXTERN void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy); -_UI_EXTERN void uiFormDelete(uiForm *f, int index); -_UI_EXTERN int uiFormPadded(uiForm *f); -_UI_EXTERN void uiFormSetPadded(uiForm *f, int padded); -_UI_EXTERN uiForm *uiNewForm(void); - -_UI_ENUM(uiAlign) { - uiAlignFill, - uiAlignStart, - uiAlignCenter, - uiAlignEnd, -}; - -_UI_ENUM(uiAt) { - uiAtLeading, - uiAtTop, - uiAtTrailing, - uiAtBottom, -}; - -typedef struct uiGrid uiGrid; -#define uiGrid(this) ((uiGrid *) (this)) -_UI_EXTERN void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign); -_UI_EXTERN void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign); -_UI_EXTERN int uiGridPadded(uiGrid *g); -_UI_EXTERN void uiGridSetPadded(uiGrid *g, int padded); -_UI_EXTERN uiGrid *uiNewGrid(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/libui/ui_darwin.h b/deps/libui/ui_darwin.h deleted file mode 100644 index c9c6ad54e9..0000000000 --- a/deps/libui/ui_darwin.h +++ /dev/null @@ -1,224 +0,0 @@ -// 7 april 2015 - -/* -This file assumes that you have imported and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls on Mac OS X. -*/ - -#ifndef __LIBUI_UI_DARWIN_H__ -#define __LIBUI_UI_DARWIN_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct uiDarwinControl uiDarwinControl; -struct uiDarwinControl { - uiControl c; - uiControl *parent; - BOOL enabled; - BOOL visible; - void (*SyncEnableState)(uiDarwinControl *, int); - void (*SetSuperview)(uiDarwinControl *, NSView *); - BOOL (*HugsTrailingEdge)(uiDarwinControl *); - BOOL (*HugsBottom)(uiDarwinControl *); - void (*ChildEdgeHuggingChanged)(uiDarwinControl *); - NSLayoutPriority (*HuggingPriority)(uiDarwinControl *, NSLayoutConstraintOrientation); - void (*SetHuggingPriority)(uiDarwinControl *, NSLayoutPriority, NSLayoutConstraintOrientation); - void (*ChildVisibilityChanged)(uiDarwinControl *); -}; -#define uiDarwinControl(this) ((uiDarwinControl *) (this)) -// TODO document -_UI_EXTERN void uiDarwinControlSyncEnableState(uiDarwinControl *, int); -_UI_EXTERN void uiDarwinControlSetSuperview(uiDarwinControl *, NSView *); -_UI_EXTERN BOOL uiDarwinControlHugsTrailingEdge(uiDarwinControl *); -_UI_EXTERN BOOL uiDarwinControlHugsBottom(uiDarwinControl *); -_UI_EXTERN void uiDarwinControlChildEdgeHuggingChanged(uiDarwinControl *); -_UI_EXTERN NSLayoutPriority uiDarwinControlHuggingPriority(uiDarwinControl *, NSLayoutConstraintOrientation); -_UI_EXTERN void uiDarwinControlSetHuggingPriority(uiDarwinControl *, NSLayoutPriority, NSLayoutConstraintOrientation); -_UI_EXTERN void uiDarwinControlChildVisibilityChanged(uiDarwinControl *); - -#define uiDarwinControlDefaultDestroy(type, handlefield) \ - static void type ## Destroy(uiControl *c) \ - { \ - [type(c)->handlefield release]; \ - uiFreeControl(c); \ - } -#define uiDarwinControlDefaultHandle(type, handlefield) \ - static uintptr_t type ## Handle(uiControl *c) \ - { \ - return (uintptr_t) (type(c)->handlefield); \ - } -#define uiDarwinControlDefaultParent(type, handlefield) \ - static uiControl *type ## Parent(uiControl *c) \ - { \ - return uiDarwinControl(c)->parent; \ - } -#define uiDarwinControlDefaultSetParent(type, handlefield) \ - static void type ## SetParent(uiControl *c, uiControl *parent) \ - { \ - uiControlVerifySetParent(c, parent); \ - uiDarwinControl(c)->parent = parent; \ - } -#define uiDarwinControlDefaultToplevel(type, handlefield) \ - static int type ## Toplevel(uiControl *c) \ - { \ - return 0; \ - } -#define uiDarwinControlDefaultVisible(type, handlefield) \ - static int type ## Visible(uiControl *c) \ - { \ - return uiDarwinControl(c)->visible; \ - } -#define uiDarwinControlDefaultShow(type, handlefield) \ - static void type ## Show(uiControl *c) \ - { \ - uiDarwinControl(c)->visible = YES; \ - [type(c)->handlefield setHidden:NO]; \ - uiDarwinNotifyVisibilityChanged(uiDarwinControl(c)); \ - } -#define uiDarwinControlDefaultHide(type, handlefield) \ - static void type ## Hide(uiControl *c) \ - { \ - uiDarwinControl(c)->visible = NO; \ - [type(c)->handlefield setHidden:YES]; \ - uiDarwinNotifyVisibilityChanged(uiDarwinControl(c)); \ - } -#define uiDarwinControlDefaultEnabled(type, handlefield) \ - static int type ## Enabled(uiControl *c) \ - { \ - return uiDarwinControl(c)->enabled; \ - } -#define uiDarwinControlDefaultEnable(type, handlefield) \ - static void type ## Enable(uiControl *c) \ - { \ - uiDarwinControl(c)->enabled = YES; \ - uiDarwinControlSyncEnableState(uiDarwinControl(c), uiControlEnabledToUser(c)); \ - } -#define uiDarwinControlDefaultDisable(type, handlefield) \ - static void type ## Disable(uiControl *c) \ - { \ - uiDarwinControl(c)->enabled = NO; \ - uiDarwinControlSyncEnableState(uiDarwinControl(c), uiControlEnabledToUser(c)); \ - } -#define uiDarwinControlDefaultSyncEnableState(type, handlefield) \ - static void type ## SyncEnableState(uiDarwinControl *c, int enabled) \ - { \ - if (uiDarwinShouldStopSyncEnableState(c, enabled)) \ - return; \ - if ([type(c)->handlefield respondsToSelector:@selector(setEnabled:)]) \ - [((id) (type(c)->handlefield)) setEnabled:enabled]; /* id cast to make compiler happy; thanks mikeash in irc.freenode.net/#macdev */ \ - } -#define uiDarwinControlDefaultSetSuperview(type, handlefield) \ - static void type ## SetSuperview(uiDarwinControl *c, NSView *superview) \ - { \ - [type(c)->handlefield setTranslatesAutoresizingMaskIntoConstraints:NO]; \ - if (superview == nil) \ - [type(c)->handlefield removeFromSuperview]; \ - else \ - [superview addSubview:type(c)->handlefield]; \ - } -#define uiDarwinControlDefaultHugsTrailingEdge(type, handlefield) \ - static BOOL type ## HugsTrailingEdge(uiDarwinControl *c) \ - { \ - return YES; /* always hug by default */ \ - } -#define uiDarwinControlDefaultHugsBottom(type, handlefield) \ - static BOOL type ## HugsBottom(uiDarwinControl *c) \ - { \ - return YES; /* always hug by default */ \ - } -#define uiDarwinControlDefaultChildEdgeHuggingChanged(type, handlefield) \ - static void type ## ChildEdgeHuggingChanged(uiDarwinControl *c) \ - { \ - /* do nothing */ \ - } -#define uiDarwinControlDefaultHuggingPriority(type, handlefield) \ - static NSLayoutPriority type ## HuggingPriority(uiDarwinControl *c, NSLayoutConstraintOrientation orientation) \ - { \ - return [type(c)->handlefield contentHuggingPriorityForOrientation:orientation]; \ - } -#define uiDarwinControlDefaultSetHuggingPriority(type, handlefield) \ - static void type ## SetHuggingPriority(uiDarwinControl *c, NSLayoutPriority priority, NSLayoutConstraintOrientation orientation) \ - { \ - [type(c)->handlefield setContentHuggingPriority:priority forOrientation:orientation]; \ - } -#define uiDarwinControlDefaultChildVisibilityChanged(type, handlefield) \ - static void type ## ChildVisibilityChanged(uiDarwinControl *c) \ - { \ - /* do nothing */ \ - } - -#define uiDarwinControlAllDefaultsExceptDestroy(type, handlefield) \ - uiDarwinControlDefaultHandle(type, handlefield) \ - uiDarwinControlDefaultParent(type, handlefield) \ - uiDarwinControlDefaultSetParent(type, handlefield) \ - uiDarwinControlDefaultToplevel(type, handlefield) \ - uiDarwinControlDefaultVisible(type, handlefield) \ - uiDarwinControlDefaultShow(type, handlefield) \ - uiDarwinControlDefaultHide(type, handlefield) \ - uiDarwinControlDefaultEnabled(type, handlefield) \ - uiDarwinControlDefaultEnable(type, handlefield) \ - uiDarwinControlDefaultDisable(type, handlefield) \ - uiDarwinControlDefaultSyncEnableState(type, handlefield) \ - uiDarwinControlDefaultSetSuperview(type, handlefield) \ - uiDarwinControlDefaultHugsTrailingEdge(type, handlefield) \ - uiDarwinControlDefaultHugsBottom(type, handlefield) \ - uiDarwinControlDefaultChildEdgeHuggingChanged(type, handlefield) \ - uiDarwinControlDefaultHuggingPriority(type, handlefield) \ - uiDarwinControlDefaultSetHuggingPriority(type, handlefield) \ - uiDarwinControlDefaultChildVisibilityChanged(type, handlefield) - -#define uiDarwinControlAllDefaults(type, handlefield) \ - uiDarwinControlDefaultDestroy(type, handlefield) \ - uiDarwinControlAllDefaultsExceptDestroy(type, handlefield) - -// TODO document -#define uiDarwinNewControl(type, var) \ - var = type(uiDarwinAllocControl(sizeof (type), type ## Signature, #type)); \ - uiControl(var)->Destroy = type ## Destroy; \ - uiControl(var)->Handle = type ## Handle; \ - uiControl(var)->Parent = type ## Parent; \ - uiControl(var)->SetParent = type ## SetParent; \ - uiControl(var)->Toplevel = type ## Toplevel; \ - uiControl(var)->Visible = type ## Visible; \ - uiControl(var)->Show = type ## Show; \ - uiControl(var)->Hide = type ## Hide; \ - uiControl(var)->Enabled = type ## Enabled; \ - uiControl(var)->Enable = type ## Enable; \ - uiControl(var)->Disable = type ## Disable; \ - uiDarwinControl(var)->SyncEnableState = type ## SyncEnableState; \ - uiDarwinControl(var)->SetSuperview = type ## SetSuperview; \ - uiDarwinControl(var)->HugsTrailingEdge = type ## HugsTrailingEdge; \ - uiDarwinControl(var)->HugsBottom = type ## HugsBottom; \ - uiDarwinControl(var)->ChildEdgeHuggingChanged = type ## ChildEdgeHuggingChanged; \ - uiDarwinControl(var)->HuggingPriority = type ## HuggingPriority; \ - uiDarwinControl(var)->SetHuggingPriority = type ## SetHuggingPriority; \ - uiDarwinControl(var)->ChildVisibilityChanged = type ## ChildVisibilityChanged; \ - uiDarwinControl(var)->visible = YES; \ - uiDarwinControl(var)->enabled = YES; -// TODO document -_UI_EXTERN uiDarwinControl *uiDarwinAllocControl(size_t n, uint32_t typesig, const char *typenamestr); - -// Use this function as a shorthand for setting control fonts. -_UI_EXTERN void uiDarwinSetControlFont(NSControl *c, NSControlSize size); - -// You can use this function from within your control implementations to return text strings that can be freed with uiFreeText(). -_UI_EXTERN char *uiDarwinNSStringToText(NSString *); - -// TODO document -_UI_EXTERN BOOL uiDarwinShouldStopSyncEnableState(uiDarwinControl *, BOOL); - -// TODO document -_UI_EXTERN void uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl *); -_UI_EXTERN void uiDarwinNotifyVisibilityChanged(uiDarwinControl *c); - -// TODO document -// TODO document that values should not be cached -_UI_EXTERN CGFloat uiDarwinMarginAmount(void *reserved); -_UI_EXTERN CGFloat uiDarwinPaddingAmount(void *reserved); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/libui/ui_unix.h b/deps/libui/ui_unix.h deleted file mode 100644 index 5a91257bdd..0000000000 --- a/deps/libui/ui_unix.h +++ /dev/null @@ -1,140 +0,0 @@ -// 7 april 2015 - -/* -This file assumes that you have included and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls on Unix systems that use GTK+ to provide their UI (currently all except Mac OS X). -*/ - -#ifndef __LIBUI_UI_UNIX_H__ -#define __LIBUI_UI_UNIX_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct uiUnixControl uiUnixControl; -struct uiUnixControl { - uiControl c; - uiControl *parent; - gboolean addedBefore; - void (*SetContainer)(uiUnixControl *, GtkContainer *, gboolean); -}; -#define uiUnixControl(this) ((uiUnixControl *) (this)) -// TODO document -_UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gboolean); - -#define uiUnixControlDefaultDestroy(type) \ - static void type ## Destroy(uiControl *c) \ - { \ - /* TODO is this safe on floating refs? */ \ - g_object_unref(type(c)->widget); \ - uiFreeControl(c); \ - } -#define uiUnixControlDefaultHandle(type) \ - static uintptr_t type ## Handle(uiControl *c) \ - { \ - return (uintptr_t) (type(c)->widget); \ - } -#define uiUnixControlDefaultParent(type) \ - static uiControl *type ## Parent(uiControl *c) \ - { \ - return uiUnixControl(c)->parent; \ - } -#define uiUnixControlDefaultSetParent(type) \ - static void type ## SetParent(uiControl *c, uiControl *parent) \ - { \ - uiControlVerifySetParent(c, parent); \ - uiUnixControl(c)->parent = parent; \ - } -#define uiUnixControlDefaultToplevel(type) \ - static int type ## Toplevel(uiControl *c) \ - { \ - return 0; \ - } -#define uiUnixControlDefaultVisible(type) \ - static int type ## Visible(uiControl *c) \ - { \ - return gtk_widget_get_visible(type(c)->widget); \ - } -#define uiUnixControlDefaultShow(type) \ - static void type ## Show(uiControl *c) \ - { \ - gtk_widget_show(type(c)->widget); \ - } -#define uiUnixControlDefaultHide(type) \ - static void type ## Hide(uiControl *c) \ - { \ - gtk_widget_hide(type(c)->widget); \ - } -#define uiUnixControlDefaultEnabled(type) \ - static int type ## Enabled(uiControl *c) \ - { \ - return gtk_widget_get_sensitive(type(c)->widget); \ - } -#define uiUnixControlDefaultEnable(type) \ - static void type ## Enable(uiControl *c) \ - { \ - gtk_widget_set_sensitive(type(c)->widget, TRUE); \ - } -#define uiUnixControlDefaultDisable(type) \ - static void type ## Disable(uiControl *c) \ - { \ - gtk_widget_set_sensitive(type(c)->widget, FALSE); \ - } -// TODO this whole addedBefore stuff is a MASSIVE HACK. -#define uiUnixControlDefaultSetContainer(type) \ - static void type ## SetContainer(uiUnixControl *c, GtkContainer *container, gboolean remove) \ - { \ - if (!uiUnixControl(c)->addedBefore) { \ - g_object_ref_sink(type(c)->widget); /* our own reference, which we release in Destroy() */ \ - gtk_widget_show(type(c)->widget); \ - uiUnixControl(c)->addedBefore = TRUE; \ - } \ - if (remove) \ - gtk_container_remove(container, type(c)->widget); \ - else \ - gtk_container_add(container, type(c)->widget); \ - } - -#define uiUnixControlAllDefaultsExceptDestroy(type) \ - uiUnixControlDefaultHandle(type) \ - uiUnixControlDefaultParent(type) \ - uiUnixControlDefaultSetParent(type) \ - uiUnixControlDefaultToplevel(type) \ - uiUnixControlDefaultVisible(type) \ - uiUnixControlDefaultShow(type) \ - uiUnixControlDefaultHide(type) \ - uiUnixControlDefaultEnabled(type) \ - uiUnixControlDefaultEnable(type) \ - uiUnixControlDefaultDisable(type) \ - uiUnixControlDefaultSetContainer(type) - -#define uiUnixControlAllDefaults(type) \ - uiUnixControlDefaultDestroy(type) \ - uiUnixControlAllDefaultsExceptDestroy(type) - -// TODO document -#define uiUnixNewControl(type, var) \ - var = type(uiUnixAllocControl(sizeof (type), type ## Signature, #type)); \ - uiControl(var)->Destroy = type ## Destroy; \ - uiControl(var)->Handle = type ## Handle; \ - uiControl(var)->Parent = type ## Parent; \ - uiControl(var)->SetParent = type ## SetParent; \ - uiControl(var)->Toplevel = type ## Toplevel; \ - uiControl(var)->Visible = type ## Visible; \ - uiControl(var)->Show = type ## Show; \ - uiControl(var)->Hide = type ## Hide; \ - uiControl(var)->Enabled = type ## Enabled; \ - uiControl(var)->Enable = type ## Enable; \ - uiControl(var)->Disable = type ## Disable; \ - uiUnixControl(var)->SetContainer = type ## SetContainer; -// TODO document -_UI_EXTERN uiUnixControl *uiUnixAllocControl(size_t n, uint32_t typesig, const char *typenamestr); - -// uiUnixStrdupText() takes the given string and produces a copy of it suitable for being freed by uiFreeText(). -_UI_EXTERN char *uiUnixStrdupText(const char *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/libui/ui_windows.h b/deps/libui/ui_windows.h deleted file mode 100644 index 69dda3666c..0000000000 --- a/deps/libui/ui_windows.h +++ /dev/null @@ -1,267 +0,0 @@ -// 21 april 2016 - -/* -This file assumes that you have included and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls in Windows. -*/ - -#ifndef __LIBUI_UI_WINDOWS_H__ -#define __LIBUI_UI_WINDOWS_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct uiWindowsSizing uiWindowsSizing; - -typedef struct uiWindowsControl uiWindowsControl; -struct uiWindowsControl { - uiControl c; - uiControl *parent; - // TODO this should be int on both os x and windows - BOOL enabled; - BOOL visible; - void (*SyncEnableState)(uiWindowsControl *, int); - void (*SetParentHWND)(uiWindowsControl *, HWND); - void (*MinimumSize)(uiWindowsControl *, int *, int *); - void (*MinimumSizeChanged)(uiWindowsControl *); - void (*LayoutRect)(uiWindowsControl *c, RECT *r); - void (*AssignControlIDZOrder)(uiWindowsControl *, LONG_PTR *, HWND *); - void (*ChildVisibilityChanged)(uiWindowsControl *); -}; -#define uiWindowsControl(this) ((uiWindowsControl *) (this)) -// TODO document -_UI_EXTERN void uiWindowsControlSyncEnableState(uiWindowsControl *, int); -_UI_EXTERN void uiWindowsControlSetParentHWND(uiWindowsControl *, HWND); -_UI_EXTERN void uiWindowsControlMinimumSize(uiWindowsControl *, int *, int *); -_UI_EXTERN void uiWindowsControlMinimumSizeChanged(uiWindowsControl *); -_UI_EXTERN void uiWindowsControlLayoutRect(uiWindowsControl *, RECT *); -_UI_EXTERN void uiWindowsControlAssignControlIDZOrder(uiWindowsControl *, LONG_PTR *, HWND *); -_UI_EXTERN void uiWindowsControlChildVisibilityChanged(uiWindowsControl *); - -// TODO document -#define uiWindowsControlDefaultDestroy(type) \ - static void type ## Destroy(uiControl *c) \ - { \ - uiWindowsEnsureDestroyWindow(type(c)->hwnd); \ - uiFreeControl(c); \ - } -#define uiWindowsControlDefaultHandle(type) \ - static uintptr_t type ## Handle(uiControl *c) \ - { \ - return (uintptr_t) (type(c)->hwnd); \ - } -#define uiWindowsControlDefaultParent(type) \ - static uiControl *type ## Parent(uiControl *c) \ - { \ - return uiWindowsControl(c)->parent; \ - } -#define uiWindowsControlDefaultSetParent(type) \ - static void type ## SetParent(uiControl *c, uiControl *parent) \ - { \ - uiControlVerifySetParent(c, parent); \ - uiWindowsControl(c)->parent = parent; \ - } -#define uiWindowsControlDefaultToplevel(type) \ - static int type ## Toplevel(uiControl *c) \ - { \ - return 0; \ - } -#define uiWindowsControlDefaultVisible(type) \ - static int type ## Visible(uiControl *c) \ - { \ - return uiWindowsControl(c)->visible; \ - } -#define uiWindowsControlDefaultShow(type) \ - static void type ## Show(uiControl *c) \ - { \ - uiWindowsControl(c)->visible = 1; \ - ShowWindow(type(c)->hwnd, SW_SHOW); \ - uiWindowsControlNotifyVisibilityChanged(uiWindowsControl(c)); \ - } -#define uiWindowsControlDefaultHide(type) \ - static void type ## Hide(uiControl *c) \ - { \ - uiWindowsControl(c)->visible = 0; \ - ShowWindow(type(c)->hwnd, SW_HIDE); \ - uiWindowsControlNotifyVisibilityChanged(uiWindowsControl(c)); \ - } -#define uiWindowsControlDefaultEnabled(type) \ - static int type ## Enabled(uiControl *c) \ - { \ - return uiWindowsControl(c)->enabled; \ - } -#define uiWindowsControlDefaultEnable(type) \ - static void type ## Enable(uiControl *c) \ - { \ - uiWindowsControl(c)->enabled = 1; \ - uiWindowsControlSyncEnableState(uiWindowsControl(c), uiControlEnabledToUser(c)); \ - } -#define uiWindowsControlDefaultDisable(type) \ - static void type ## Disable(uiControl *c) \ - { \ - uiWindowsControl(c)->enabled = 0; \ - uiWindowsControlSyncEnableState(uiWindowsControl(c), uiControlEnabledToUser(c)); \ - } -#define uiWindowsControlDefaultSyncEnableState(type) \ - static void type ## SyncEnableState(uiWindowsControl *c, int enabled) \ - { \ - if (uiWindowsShouldStopSyncEnableState(c, enabled)) \ - return; \ - EnableWindow(type(c)->hwnd, enabled); \ - } -#define uiWindowsControlDefaultSetParentHWND(type) \ - static void type ## SetParentHWND(uiWindowsControl *c, HWND parent) \ - { \ - uiWindowsEnsureSetParentHWND(type(c)->hwnd, parent); \ - } -// note that there is no uiWindowsControlDefaultMinimumSize(); you MUST define this yourself! -#define uiWindowsControlDefaultMinimumSizeChanged(type) \ - static void type ## MinimumSizeChanged(uiWindowsControl *c) \ - { \ - if (uiWindowsControlTooSmall(c)) { \ - uiWindowsControlContinueMinimumSizeChanged(c); \ - return; \ - } \ - /* otherwise do nothing; we have no children */ \ - } -#define uiWindowsControlDefaultLayoutRect(type) \ - static void type ## LayoutRect(uiWindowsControl *c, RECT *r) \ - { \ - /* use the window rect as we include the non-client area in the sizes */ \ - uiWindowsEnsureGetWindowRect(type(c)->hwnd, r); \ - } -#define uiWindowsControlDefaultAssignControlIDZOrder(type) \ - static void type ## AssignControlIDZOrder(uiWindowsControl *c, LONG_PTR *controlID, HWND *insertAfter) \ - { \ - uiWindowsEnsureAssignControlIDZOrder(type(c)->hwnd, controlID, insertAfter); \ - } -#define uiWindowsControlDefaultChildVisibilityChanged(type) \ - static void type ## ChildVisibilityChanged(uiWindowsControl *c) \ - { \ - /* do nothing */ \ - } - -#define uiWindowsControlAllDefaultsExceptDestroy(type) \ - uiWindowsControlDefaultHandle(type) \ - uiWindowsControlDefaultParent(type) \ - uiWindowsControlDefaultSetParent(type) \ - uiWindowsControlDefaultToplevel(type) \ - uiWindowsControlDefaultVisible(type) \ - uiWindowsControlDefaultShow(type) \ - uiWindowsControlDefaultHide(type) \ - uiWindowsControlDefaultEnabled(type) \ - uiWindowsControlDefaultEnable(type) \ - uiWindowsControlDefaultDisable(type) \ - uiWindowsControlDefaultSyncEnableState(type) \ - uiWindowsControlDefaultSetParentHWND(type) \ - uiWindowsControlDefaultMinimumSizeChanged(type) \ - uiWindowsControlDefaultLayoutRect(type) \ - uiWindowsControlDefaultAssignControlIDZOrder(type) \ - uiWindowsControlDefaultChildVisibilityChanged(type) - -#define uiWindowsControlAllDefaults(type) \ - uiWindowsControlDefaultDestroy(type) \ - uiWindowsControlAllDefaultsExceptDestroy(type) - -// TODO document -#define uiWindowsNewControl(type, var) \ - var = type(uiWindowsAllocControl(sizeof (type), type ## Signature, #type)); \ - uiControl(var)->Destroy = type ## Destroy; \ - uiControl(var)->Handle = type ## Handle; \ - uiControl(var)->Parent = type ## Parent; \ - uiControl(var)->SetParent = type ## SetParent; \ - uiControl(var)->Toplevel = type ## Toplevel; \ - uiControl(var)->Visible = type ## Visible; \ - uiControl(var)->Show = type ## Show; \ - uiControl(var)->Hide = type ## Hide; \ - uiControl(var)->Enabled = type ## Enabled; \ - uiControl(var)->Enable = type ## Enable; \ - uiControl(var)->Disable = type ## Disable; \ - uiWindowsControl(var)->SyncEnableState = type ## SyncEnableState; \ - uiWindowsControl(var)->SetParentHWND = type ## SetParentHWND; \ - uiWindowsControl(var)->MinimumSize = type ## MinimumSize; \ - uiWindowsControl(var)->MinimumSizeChanged = type ## MinimumSizeChanged; \ - uiWindowsControl(var)->LayoutRect = type ## LayoutRect; \ - uiWindowsControl(var)->AssignControlIDZOrder = type ## AssignControlIDZOrder; \ - uiWindowsControl(var)->ChildVisibilityChanged = type ## ChildVisibilityChanged; \ - uiWindowsControl(var)->visible = 1; \ - uiWindowsControl(var)->enabled = 1; -// TODO document -_UI_EXTERN uiWindowsControl *uiWindowsAllocControl(size_t n, uint32_t typesig, const char *typenamestr); - -// TODO document -_UI_EXTERN HWND uiWindowsEnsureCreateControlHWND(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, HINSTANCE hInstance, LPVOID lpParam, BOOL useStandardControlFont); - -// TODO document -_UI_EXTERN void uiWindowsEnsureDestroyWindow(HWND hwnd); - -// TODO document -// TODO document that this should only be used in SetParentHWND() implementations -_UI_EXTERN void uiWindowsEnsureSetParentHWND(HWND hwnd, HWND parent); - -// TODO document -_UI_EXTERN void uiWindowsEnsureAssignControlIDZOrder(HWND hwnd, LONG_PTR *controlID, HWND *insertAfter); - -// TODO document -_UI_EXTERN void uiWindowsEnsureGetClientRect(HWND hwnd, RECT *r); -_UI_EXTERN void uiWindowsEnsureGetWindowRect(HWND hwnd, RECT *r); - -// TODO document -_UI_EXTERN char *uiWindowsWindowText(HWND hwnd); -_UI_EXTERN void uiWindowsSetWindowText(HWND hwnd, const char *text); - -// TODO document -_UI_EXTERN int uiWindowsWindowTextWidth(HWND hwnd); - -// TODO document -// TODO point out this should only be used in a resize cycle -_UI_EXTERN void uiWindowsEnsureMoveWindowDuringResize(HWND hwnd, int x, int y, int width, int height); - -// TODO document -_UI_EXTERN void uiWindowsRegisterWM_COMMANDHandler(HWND hwnd, BOOL (*handler)(uiControl *, HWND, WORD, LRESULT *), uiControl *c); -_UI_EXTERN void uiWindowsUnregisterWM_COMMANDHandler(HWND hwnd); - -// TODO document -_UI_EXTERN void uiWindowsRegisterWM_NOTIFYHandler(HWND hwnd, BOOL (*handler)(uiControl *, HWND, NMHDR *, LRESULT *), uiControl *c); -_UI_EXTERN void uiWindowsUnregisterWM_NOTIFYHandler(HWND hwnd); - -// TODO document -_UI_EXTERN void uiWindowsRegisterWM_HSCROLLHandler(HWND hwnd, BOOL (*handler)(uiControl *, HWND, WORD, LRESULT *), uiControl *c); -_UI_EXTERN void uiWindowsUnregisterWM_HSCROLLHandler(HWND hwnd); - -// TODO document -_UI_EXTERN void uiWindowsRegisterReceiveWM_WININICHANGE(HWND hwnd); -_UI_EXTERN void uiWindowsUnregisterReceiveWM_WININICHANGE(HWND hwnd); - -// TODO document -typedef struct uiWindowsSizing uiWindowsSizing; -struct uiWindowsSizing { - int BaseX; - int BaseY; - LONG InternalLeading; -}; -_UI_EXTERN void uiWindowsGetSizing(HWND hwnd, uiWindowsSizing *sizing); -_UI_EXTERN void uiWindowsSizingDlgUnitsToPixels(uiWindowsSizing *sizing, int *x, int *y); -_UI_EXTERN void uiWindowsSizingStandardPadding(uiWindowsSizing *sizing, int *x, int *y); - -// TODO document -_UI_EXTERN HWND uiWindowsMakeContainer(uiWindowsControl *c, void (*onResize)(uiWindowsControl *)); - -// TODO document -_UI_EXTERN BOOL uiWindowsControlTooSmall(uiWindowsControl *c); -_UI_EXTERN void uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl *c); - -// TODO document -_UI_EXTERN void uiWindowsControlAssignSoleControlIDZOrder(uiWindowsControl *); - -// TODO document -_UI_EXTERN BOOL uiWindowsShouldStopSyncEnableState(uiWindowsControl *c, int enabled); - -// TODO document -_UI_EXTERN void uiWindowsControlNotifyVisibilityChanged(uiWindowsControl *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/libui/unix/CMakeLists.txt b/deps/libui/unix/CMakeLists.txt deleted file mode 100644 index 9300bcb701..0000000000 --- a/deps/libui/unix/CMakeLists.txt +++ /dev/null @@ -1,85 +0,0 @@ -# 3 june 2016 - -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED gtk+-3.0) - -list(APPEND _LIBUI_SOURCES - unix/alloc.c - unix/area.c - unix/box.c - unix/button.c - unix/cellrendererbutton.c - unix/checkbox.c - unix/child.c - unix/colorbutton.c - unix/combobox.c - unix/control.c - unix/datetimepicker.c - unix/debug.c - unix/draw.c - unix/drawmatrix.c - unix/drawpath.c - unix/drawtext.c - unix/editablecombo.c - unix/entry.c - unix/fontbutton.c - unix/form.c - unix/future.c - unix/graphemes.c - unix/grid.c - unix/group.c - unix/image.c - unix/label.c - unix/main.c - unix/menu.c - unix/multilineentry.c - unix/progressbar.c - unix/radiobuttons.c - unix/separator.c - unix/slider.c - unix/spinbox.c - unix/stddialogs.c - unix/tab.c - unix/text.c - unix/util.c - unix/window.c -) -set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) - -list(APPEND _LIBUI_INCLUDEDIRS - unix -) -set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE) - -set(_LIBUINAME libui PARENT_SCOPE) -if(NOT BUILD_SHARED_LIBS) - set(_LIBUINAME libui-temporary PARENT_SCOPE) -endif() -macro(_handle_static) - set_target_properties(${_LIBUINAME} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") - set(_aname $) - set(_oname libui-combined.o) - add_custom_command( - OUTPUT ${_oname} - COMMAND - ld -r --whole-archive ${_aname} -o ${_oname} - COMMAND - objcopy --localize-hidden ${_oname} - COMMENT "Removing hidden symbols") - add_library(libui STATIC ${_oname}) - # otherwise cmake won't know which linker to use - set_target_properties(libui PROPERTIES - LINKER_LANGUAGE C) - set(_aname) - set(_oname) -endmacro() - -# TODO the other variables don't work? -set(_LIBUI_CFLAGS - ${GTK_CFLAGS} -PARENT_SCOPE) - -set(_LIBUI_LIBS - ${GTK_LDFLAGS} m ${CMAKE_DL_LIBS} -PARENT_SCOPE) diff --git a/deps/libui/unix/alloc.c b/deps/libui/unix/alloc.c deleted file mode 100644 index 2561efa6e2..0000000000 --- a/deps/libui/unix/alloc.c +++ /dev/null @@ -1,84 +0,0 @@ -// 7 april 2015 -#include -#include "uipriv_unix.h" - -static GPtrArray *allocations; - -#define UINT8(p) ((uint8_t *) (p)) -#define PVOID(p) ((void *) (p)) -#define EXTRA (sizeof (size_t) + sizeof (const char **)) -#define DATA(p) PVOID(UINT8(p) + EXTRA) -#define BASE(p) PVOID(UINT8(p) - EXTRA) -#define SIZE(p) ((size_t *) (p)) -#define CCHAR(p) ((const char **) (p)) -#define TYPE(p) CCHAR(UINT8(p) + sizeof (size_t)) - -void initAlloc(void) -{ - allocations = g_ptr_array_new(); -} - -static void uninitComplain(gpointer ptr, gpointer data) -{ - char **str = (char **) data; - char *str2; - - if (*str == NULL) - *str = g_strdup_printf(""); - str2 = g_strdup_printf("%s%p %s\n", *str, ptr, *TYPE(ptr)); - g_free(*str); - *str = str2; -} - -void uninitAlloc(void) -{ - char *str = NULL; - - if (allocations->len == 0) { - g_ptr_array_free(allocations, TRUE); - return; - } - g_ptr_array_foreach(allocations, uninitComplain, &str); - userbug("Some data was leaked; either you left a uiControl lying around or there's a bug in libui itself. Leaked data:\n%s", str); - g_free(str); -} - -void *uiAlloc(size_t size, const char *type) -{ - void *out; - - out = g_malloc0(EXTRA + size); - *SIZE(out) = size; - *TYPE(out) = type; - g_ptr_array_add(allocations, out); - return DATA(out); -} - -void *uiRealloc(void *p, size_t new, const char *type) -{ - void *out; - size_t *s; - - if (p == NULL) - return uiAlloc(new, type); - p = BASE(p); - out = g_realloc(p, EXTRA + new); - s = SIZE(out); - if (new <= *s) - memset(((uint8_t *) DATA(out)) + *s, 0, new - *s); - *s = new; - if (g_ptr_array_remove(allocations, p) == FALSE) - implbug("%p not found in allocations array in uiRealloc()", p); - g_ptr_array_add(allocations, out); - return DATA(out); -} - -void uiFree(void *p) -{ - if (p == NULL) - implbug("attempt to uiFree(NULL)"); - p = BASE(p); - g_free(p); - if (g_ptr_array_remove(allocations, p) == FALSE) - implbug("%p not found in allocations array in uiFree()", p); -} diff --git a/deps/libui/unix/area.c b/deps/libui/unix/area.c deleted file mode 100644 index c46447cc33..0000000000 --- a/deps/libui/unix/area.c +++ /dev/null @@ -1,633 +0,0 @@ -// 4 september 2015 -#include "uipriv_unix.h" - -// notes: -// - G_DECLARE_DERIVABLE/FINAL_INTERFACE() requires glib 2.44 and that's starting with debian stretch (testing) (GTK+ 3.18) and ubuntu 15.04 (GTK+ 3.14) - debian jessie has 2.42 (GTK+ 3.14) -#define areaWidgetType (areaWidget_get_type()) -#define areaWidget(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), areaWidgetType, areaWidget)) -#define isAreaWidget(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), areaWidgetType)) -#define areaWidgetClass(class) (G_TYPE_CHECK_CLASS_CAST((class), areaWidgetType, areaWidgetClass)) -#define isAreaWidgetClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), areaWidget)) -#define getAreaWidgetClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), areaWidgetType, areaWidgetClass)) - -typedef struct areaWidget areaWidget; -typedef struct areaWidgetClass areaWidgetClass; - -struct areaWidget { - GtkDrawingArea parent_instance; - uiArea *a; - // construct-only parameters aare not set until after the init() function has returned - // we need this particular object available during init(), so put it here instead of in uiArea - // keep a pointer in uiArea for convenience, though - clickCounter cc; -}; - -struct areaWidgetClass { - GtkDrawingAreaClass parent_class; -}; - -struct uiArea { - uiUnixControl c; - GtkWidget *widget; // either swidget or areaWidget depending on whether it is scrolling - - GtkWidget *swidget; - GtkContainer *scontainer; - GtkScrolledWindow *sw; - - GtkWidget *areaWidget; - GtkDrawingArea *drawingArea; - areaWidget *area; - - uiAreaHandler *ah; - - gboolean scrolling; - int scrollWidth; - int scrollHeight; - - // note that this is a pointer; see above - clickCounter *cc; - - // for user window drags - GdkEventButton *dragevent; -}; - -G_DEFINE_TYPE(areaWidget, areaWidget, GTK_TYPE_DRAWING_AREA) - -static void areaWidget_init(areaWidget *aw) -{ - // for events - gtk_widget_add_events(GTK_WIDGET(aw), - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - - gtk_widget_set_can_focus(GTK_WIDGET(aw), TRUE); - - clickCounterReset(&(aw->cc)); -} - -static void areaWidget_dispose(GObject *obj) -{ - G_OBJECT_CLASS(areaWidget_parent_class)->dispose(obj); -} - -static void areaWidget_finalize(GObject *obj) -{ - G_OBJECT_CLASS(areaWidget_parent_class)->finalize(obj); -} - -static void areaWidget_size_allocate(GtkWidget *w, GtkAllocation *allocation) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - - // GtkDrawingArea has a size_allocate() implementation; we need to call it - // this will call gtk_widget_set_allocation() for us - GTK_WIDGET_CLASS(areaWidget_parent_class)->size_allocate(w, allocation); - - if (!a->scrolling) - // we must redraw everything on resize because Windows requires it - gtk_widget_queue_resize(w); -} - -static void loadAreaSize(uiArea *a, double *width, double *height) -{ - GtkAllocation allocation; - - *width = 0; - *height = 0; - // don't provide size information for scrolling areas - if (!a->scrolling) { - gtk_widget_get_allocation(a->areaWidget, &allocation); - // these are already in drawing space coordinates - // for drawing, the size of drawing space has the same value as the widget allocation - // thanks to tristan in irc.gimp.net/#gtk+ - *width = allocation.width; - *height = allocation.height; - } -} - -static gboolean areaWidget_draw(GtkWidget *w, cairo_t *cr) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - uiAreaDrawParams dp; - double clipX0, clipY0, clipX1, clipY1; - - dp.Context = newContext(cr); - - loadAreaSize(a, &(dp.AreaWidth), &(dp.AreaHeight)); - - cairo_clip_extents(cr, &clipX0, &clipY0, &clipX1, &clipY1); - dp.ClipX = clipX0; - dp.ClipY = clipY0; - dp.ClipWidth = clipX1 - clipX0; - dp.ClipHeight = clipY1 - clipY0; - - // no need to save or restore the graphics state to reset transformations; GTK+ does that for us - (*(a->ah->Draw))(a->ah, a, &dp); - - freeContext(dp.Context); - return FALSE; -} - -// to do this properly for scrolling areas, we need to -// - return the same value for min and nat -// - call gtk_widget_queue_resize() when the size changes -// thanks to Company in irc.gimp.net/#gtk+ -static void areaWidget_get_preferred_height(GtkWidget *w, gint *min, gint *nat) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - - // always chain up just in case - GTK_WIDGET_CLASS(areaWidget_parent_class)->get_preferred_height(w, min, nat); - if (a->scrolling) { - *min = a->scrollHeight; - *nat = a->scrollHeight; - } -} - -static void areaWidget_get_preferred_width(GtkWidget *w, gint *min, gint *nat) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - - // always chain up just in case - GTK_WIDGET_CLASS(areaWidget_parent_class)->get_preferred_width(w, min, nat); - if (a->scrolling) { - *min = a->scrollWidth; - *nat = a->scrollWidth; - } -} - -static guint translateModifiers(guint state, GdkWindow *window) -{ - GdkModifierType statetype; - - // GDK doesn't initialize the modifier flags fully; we have to explicitly tell it to (thanks to Daniel_S and daniels (two different people) in irc.gimp.net/#gtk+) - statetype = state; - gdk_keymap_add_virtual_modifiers( - gdk_keymap_get_for_display(gdk_window_get_display(window)), - &statetype); - return statetype; -} - -static uiModifiers toModifiers(guint state) -{ - uiModifiers m; - - m = 0; - if ((state & GDK_CONTROL_MASK) != 0) - m |= uiModifierCtrl; - if ((state & GDK_META_MASK) != 0) - m |= uiModifierAlt; - if ((state & GDK_MOD1_MASK) != 0) // GTK+ itself requires this to be Alt (just read through gtkaccelgroup.c) - m |= uiModifierAlt; - if ((state & GDK_SHIFT_MASK) != 0) - m |= uiModifierShift; - if ((state & GDK_SUPER_MASK) != 0) - m |= uiModifierSuper; - return m; -} - -// capture on drag is done automatically on GTK+ -static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble x, gdouble y, guint state, GdkWindow *window) -{ - // on GTK+, mouse buttons 4-7 are for scrolling; if we got here, that's a mistake - if (mb >= 4 && mb <= 7) - return; - // if the button ID >= 8, continue counting from 4, as in the MouseEvent spec - if (me->Down >= 8) - me->Down -= 4; - if (me->Up >= 8) - me->Up -= 4; - - state = translateModifiers(state, window); - me->Modifiers = toModifiers(state); - - // the mb != # checks exclude the Up/Down button from Held - me->Held1To64 = 0; - if (mb != 1 && (state & GDK_BUTTON1_MASK) != 0) - me->Held1To64 |= 1 << 0; - if (mb != 2 && (state & GDK_BUTTON2_MASK) != 0) - me->Held1To64 |= 1 << 1; - if (mb != 3 && (state & GDK_BUTTON3_MASK) != 0) - me->Held1To64 |= 1 << 2; - // don't check GDK_BUTTON4_MASK or GDK_BUTTON5_MASK because those are for the scrolling buttons mentioned above - // GDK expressly does not support any more buttons in the GdkModifierType; see https://git.gnome.org/browse/gtk+/tree/gdk/x11/gdkdevice-xi2.c#n763 (thanks mclasen in irc.gimp.net/#gtk+) - - // these are already in drawing space coordinates - // the size of drawing space has the same value as the widget allocation - // thanks to tristan in irc.gimp.net/#gtk+ - me->X = x; - me->Y = y; - - loadAreaSize(a, &(me->AreaWidth), &(me->AreaHeight)); - - (*(a->ah->MouseEvent))(a->ah, a, me); -} - -static gboolean areaWidget_button_press_event(GtkWidget *w, GdkEventButton *e) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - gint maxTime, maxDistance; - GtkSettings *settings; - uiAreaMouseEvent me; - - // clicking doesn't automatically transfer keyboard focus; we must do so manually (thanks tristan in irc.gimp.net/#gtk+) - gtk_widget_grab_focus(w); - - // we handle multiple clicks ourselves here, in the same way as we do on Windows - if (e->type != GDK_BUTTON_PRESS) - // ignore GDK's generated double-clicks and beyond - return GDK_EVENT_PROPAGATE; - settings = gtk_widget_get_settings(w); - g_object_get(settings, - "gtk-double-click-time", &maxTime, - "gtk-double-click-distance", &maxDistance, - NULL); - // don't unref settings; it's transfer-none (thanks gregier in irc.gimp.net/#gtk+) - // e->time is guint32 - // e->x and e->y are floating-point; just make them 32-bit integers - // maxTime and maxDistance... are gint, which *should* fit, hopefully... - me.Count = clickCounterClick(a->cc, me.Down, - e->x, e->y, - e->time, maxTime, - maxDistance, maxDistance); - - me.Down = e->button; - me.Up = 0; - - // and set things up for window drags - a->dragevent = e; - finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window); - a->dragevent = NULL; - return GDK_EVENT_PROPAGATE; -} - -static gboolean areaWidget_button_release_event(GtkWidget *w, GdkEventButton *e) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - uiAreaMouseEvent me; - - me.Down = 0; - me.Up = e->button; - me.Count = 0; - finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window); - return GDK_EVENT_PROPAGATE; -} - -static gboolean areaWidget_motion_notify_event(GtkWidget *w, GdkEventMotion *e) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - uiAreaMouseEvent me; - - me.Down = 0; - me.Up = 0; - me.Count = 0; - finishMouseEvent(a, &me, 0, e->x, e->y, e->state, e->window); - return GDK_EVENT_PROPAGATE; -} - -// we want switching away from the control to reset the double-click counter, like with WM_ACTIVATE on Windows -// according to tristan in irc.gimp.net/#gtk+, doing this on both enter-notify-event and leave-notify-event is correct (and it seems to be true in my own tests; plus the events DO get sent when switching programs with the keyboard (just pointing that out)) -static gboolean onCrossing(areaWidget *aw, int left) -{ - uiArea *a = aw->a; - - (*(a->ah->MouseCrossed))(a->ah, a, left); - clickCounterReset(a->cc); - return GDK_EVENT_PROPAGATE; -} - -static gboolean areaWidget_enter_notify_event(GtkWidget *w, GdkEventCrossing *e) -{ - return onCrossing(areaWidget(w), 0); -} - -static gboolean areaWidget_leave_notify_event(GtkWidget *w, GdkEventCrossing *e) -{ - return onCrossing(areaWidget(w), 1); -} - -// note: there is no equivalent to WM_CAPTURECHANGED on GTK+; there literally is no way to break a grab like that (at least not on X11 and Wayland) -// even if I invoke the task switcher and switch processes, the mouse grab will still be held until I let go of all buttons -// therefore, no DragBroken() - -// we use GDK_KEY_Print as a sentinel because libui will never support the print screen key; that key belongs to the user - -static const struct { - guint keyval; - uiExtKey extkey; -} extKeys[] = { - { GDK_KEY_Escape, uiExtKeyEscape }, - { GDK_KEY_Insert, uiExtKeyInsert }, - { GDK_KEY_Delete, uiExtKeyDelete }, - { GDK_KEY_Home, uiExtKeyHome }, - { GDK_KEY_End, uiExtKeyEnd }, - { GDK_KEY_Page_Up, uiExtKeyPageUp }, - { GDK_KEY_Page_Down, uiExtKeyPageDown }, - { GDK_KEY_Up, uiExtKeyUp }, - { GDK_KEY_Down, uiExtKeyDown }, - { GDK_KEY_Left, uiExtKeyLeft }, - { GDK_KEY_Right, uiExtKeyRight }, - { GDK_KEY_F1, uiExtKeyF1 }, - { GDK_KEY_F2, uiExtKeyF2 }, - { GDK_KEY_F3, uiExtKeyF3 }, - { GDK_KEY_F4, uiExtKeyF4 }, - { GDK_KEY_F5, uiExtKeyF5 }, - { GDK_KEY_F6, uiExtKeyF6 }, - { GDK_KEY_F7, uiExtKeyF7 }, - { GDK_KEY_F8, uiExtKeyF8 }, - { GDK_KEY_F9, uiExtKeyF9 }, - { GDK_KEY_F10, uiExtKeyF10 }, - { GDK_KEY_F11, uiExtKeyF11 }, - { GDK_KEY_F12, uiExtKeyF12 }, - // numpad numeric keys and . are handled in events.c - { GDK_KEY_KP_Enter, uiExtKeyNEnter }, - { GDK_KEY_KP_Add, uiExtKeyNAdd }, - { GDK_KEY_KP_Subtract, uiExtKeyNSubtract }, - { GDK_KEY_KP_Multiply, uiExtKeyNMultiply }, - { GDK_KEY_KP_Divide, uiExtKeyNDivide }, - { GDK_KEY_Print, 0 }, -}; - -static const struct { - guint keyval; - uiModifiers mod; -} modKeys[] = { - { GDK_KEY_Control_L, uiModifierCtrl }, - { GDK_KEY_Control_R, uiModifierCtrl }, - { GDK_KEY_Alt_L, uiModifierAlt }, - { GDK_KEY_Alt_R, uiModifierAlt }, - { GDK_KEY_Meta_L, uiModifierAlt }, - { GDK_KEY_Meta_R, uiModifierAlt }, - { GDK_KEY_Shift_L, uiModifierShift }, - { GDK_KEY_Shift_R, uiModifierShift }, - { GDK_KEY_Super_L, uiModifierSuper }, - { GDK_KEY_Super_R, uiModifierSuper }, - { GDK_KEY_Print, 0 }, -}; - -static int areaKeyEvent(uiArea *a, int up, GdkEventKey *e) -{ - uiAreaKeyEvent ke; - guint state; - int i; - - ke.Key = 0; - ke.ExtKey = 0; - ke.Modifier = 0; - - state = translateModifiers(e->state, e->window); - ke.Modifiers = toModifiers(state); - - ke.Up = up; - - for (i = 0; extKeys[i].keyval != GDK_KEY_Print; i++) - if (extKeys[i].keyval == e->keyval) { - ke.ExtKey = extKeys[i].extkey; - goto keyFound; - } - - for (i = 0; modKeys[i].keyval != GDK_KEY_Print; i++) - if (modKeys[i].keyval == e->keyval) { - ke.Modifier = modKeys[i].mod; - // don't include the modifier in ke.Modifiers - ke.Modifiers &= ~ke.Modifier; - goto keyFound; - } - - if (fromScancode(e->hardware_keycode - 8, &ke)) - goto keyFound; - - // no supported key found; treat as unhandled - return 0; - -keyFound: - return (*(a->ah->KeyEvent))(a->ah, a, &ke); -} - -static gboolean areaWidget_key_press_event(GtkWidget *w, GdkEventKey *e) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - - if (areaKeyEvent(a, 0, e)) - return GDK_EVENT_STOP; - return GDK_EVENT_PROPAGATE; -} - -static gboolean areaWidget_key_release_event(GtkWidget *w, GdkEventKey *e) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - - if (areaKeyEvent(a, 1, e)) - return GDK_EVENT_STOP; - return GDK_EVENT_PROPAGATE; -} - -enum { - pArea = 1, - nProps, -}; - -static GParamSpec *pspecArea; - -static void areaWidget_set_property(GObject *obj, guint prop, const GValue *value, GParamSpec *pspec) -{ - areaWidget *aw = areaWidget(obj); - - switch (prop) { - case pArea: - aw->a = (uiArea *) g_value_get_pointer(value); - aw->a->cc = &(aw->cc); - return; - } - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec); -} - -static void areaWidget_get_property(GObject *obj, guint prop, GValue *value, GParamSpec *pspec) -{ - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec); -} - -static void areaWidget_class_init(areaWidgetClass *class) -{ - G_OBJECT_CLASS(class)->dispose = areaWidget_dispose; - G_OBJECT_CLASS(class)->finalize = areaWidget_finalize; - G_OBJECT_CLASS(class)->set_property = areaWidget_set_property; - G_OBJECT_CLASS(class)->get_property = areaWidget_get_property; - - GTK_WIDGET_CLASS(class)->size_allocate = areaWidget_size_allocate; - GTK_WIDGET_CLASS(class)->draw = areaWidget_draw; - GTK_WIDGET_CLASS(class)->get_preferred_height = areaWidget_get_preferred_height; - GTK_WIDGET_CLASS(class)->get_preferred_width = areaWidget_get_preferred_width; - GTK_WIDGET_CLASS(class)->button_press_event = areaWidget_button_press_event; - GTK_WIDGET_CLASS(class)->button_release_event = areaWidget_button_release_event; - GTK_WIDGET_CLASS(class)->motion_notify_event = areaWidget_motion_notify_event; - GTK_WIDGET_CLASS(class)->enter_notify_event = areaWidget_enter_notify_event; - GTK_WIDGET_CLASS(class)->leave_notify_event = areaWidget_leave_notify_event; - GTK_WIDGET_CLASS(class)->key_press_event = areaWidget_key_press_event; - GTK_WIDGET_CLASS(class)->key_release_event = areaWidget_key_release_event; - - pspecArea = g_param_spec_pointer("libui-area", - "libui-area", - "uiArea.", - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - g_object_class_install_property(G_OBJECT_CLASS(class), pArea, pspecArea); -} - -// control implementation - -uiUnixControlAllDefaults(uiArea) - -void uiAreaSetSize(uiArea *a, int width, int height) -{ - if (!a->scrolling) - userbug("You cannot call uiAreaSetSize() on a non-scrolling uiArea. (area: %p)", a); - a->scrollWidth = width; - a->scrollHeight = height; - gtk_widget_queue_resize(a->areaWidget); -} - -void uiAreaQueueRedrawAll(uiArea *a) -{ - gtk_widget_queue_draw(a->areaWidget); -} - -void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height) -{ - // TODO - // TODO adjust adjustments and find source for that -} - -void uiAreaBeginUserWindowMove(uiArea *a) -{ - GtkWidget *toplevel; - - if (a->dragevent == NULL) - userbug("cannot call uiAreaBeginUserWindowMove() outside of a Mouse() with Down != 0"); - // TODO don't we have a libui function for this? did I scrap it? - // TODO widget or areaWidget? - toplevel = gtk_widget_get_toplevel(a->widget); - if (toplevel == NULL) { - // TODO - return; - } - // the docs say to do this - if (!gtk_widget_is_toplevel(toplevel)) { - // TODO - return; - } - if (!GTK_IS_WINDOW(toplevel)) { - // TODO - return; - } - gtk_window_begin_move_drag(GTK_WINDOW(toplevel), - a->dragevent->button, - a->dragevent->x_root, // TODO are these correct? - a->dragevent->y_root, - a->dragevent->time); -} - -static const GdkWindowEdge edges[] = { - [uiWindowResizeEdgeLeft] = GDK_WINDOW_EDGE_WEST, - [uiWindowResizeEdgeTop] = GDK_WINDOW_EDGE_NORTH, - [uiWindowResizeEdgeRight] = GDK_WINDOW_EDGE_EAST, - [uiWindowResizeEdgeBottom] = GDK_WINDOW_EDGE_SOUTH, - [uiWindowResizeEdgeTopLeft] = GDK_WINDOW_EDGE_NORTH_WEST, - [uiWindowResizeEdgeTopRight] = GDK_WINDOW_EDGE_NORTH_EAST, - [uiWindowResizeEdgeBottomLeft] = GDK_WINDOW_EDGE_SOUTH_WEST, - [uiWindowResizeEdgeBottomRight] = GDK_WINDOW_EDGE_SOUTH_EAST, -}; - -void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge) -{ - GtkWidget *toplevel; - - if (a->dragevent == NULL) - userbug("cannot call uiAreaBeginUserWindowResize() outside of a Mouse() with Down != 0"); - // TODO don't we have a libui function for this? did I scrap it? - // TODO widget or areaWidget? - toplevel = gtk_widget_get_toplevel(a->widget); - if (toplevel == NULL) { - // TODO - return; - } - // the docs say to do this - if (!gtk_widget_is_toplevel(toplevel)) { - // TODO - return; - } - if (!GTK_IS_WINDOW(toplevel)) { - // TODO - return; - } - gtk_window_begin_resize_drag(GTK_WINDOW(toplevel), - edges[edge], - a->dragevent->button, - a->dragevent->x_root, // TODO are these correct? - a->dragevent->y_root, - a->dragevent->time); -} - -uiArea *uiNewArea(uiAreaHandler *ah) -{ - uiArea *a; - - uiUnixNewControl(uiArea, a); - - a->ah = ah; - a->scrolling = FALSE; - - a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType, - "libui-area", a, - NULL)); - a->drawingArea = GTK_DRAWING_AREA(a->areaWidget); - a->area = areaWidget(a->areaWidget); - - a->widget = a->areaWidget; - - return a; -} - -uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height) -{ - uiArea *a; - - uiUnixNewControl(uiArea, a); - - a->ah = ah; - a->scrolling = TRUE; - a->scrollWidth = width; - a->scrollHeight = height; - - a->swidget = gtk_scrolled_window_new(NULL, NULL); - a->scontainer = GTK_CONTAINER(a->swidget); - a->sw = GTK_SCROLLED_WINDOW(a->swidget); - - a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType, - "libui-area", a, - NULL)); - a->drawingArea = GTK_DRAWING_AREA(a->areaWidget); - a->area = areaWidget(a->areaWidget); - - a->widget = a->swidget; - - gtk_container_add(a->scontainer, a->areaWidget); - // and make the area visible; only the scrolled window's visibility is controlled by libui - gtk_widget_show(a->areaWidget); - - return a; -} diff --git a/deps/libui/unix/box.c b/deps/libui/unix/box.c deleted file mode 100644 index 23fb7f7c6c..0000000000 --- a/deps/libui/unix/box.c +++ /dev/null @@ -1,159 +0,0 @@ -// 7 april 2015 -#include "uipriv_unix.h" - -struct boxChild { - uiControl *c; - int stretchy; - gboolean oldhexpand; - GtkAlign oldhalign; - gboolean oldvexpand; - GtkAlign oldvalign; -}; - -struct uiBox { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkBox *box; - GArray *controls; - int vertical; - int padded; - GtkSizeGroup *stretchygroup; // ensures all stretchy controls have the same size -}; - -uiUnixControlAllDefaultsExceptDestroy(uiBox) - -#define ctrl(b, i) &g_array_index(b->controls, struct boxChild, i) - -static void uiBoxDestroy(uiControl *c) -{ - uiBox *b = uiBox(c); - struct boxChild *bc; - guint i; - - // kill the size group - g_object_unref(b->stretchygroup); - // free all controls - for (i = 0; i < b->controls->len; i++) { - bc = ctrl(b, i); - uiControlSetParent(bc->c, NULL); - // and make sure the widget itself stays alive - uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE); - uiControlDestroy(bc->c); - } - g_array_free(b->controls, TRUE); - // and then ourselves - g_object_unref(b->widget); - uiFreeControl(uiControl(b)); -} - -void uiBoxAppend(uiBox *b, uiControl *c, int stretchy) -{ - struct boxChild bc; - GtkWidget *widget; - - bc.c = c; - bc.stretchy = stretchy; - widget = GTK_WIDGET(uiControlHandle(bc.c)); - bc.oldhexpand = gtk_widget_get_hexpand(widget); - bc.oldhalign = gtk_widget_get_halign(widget); - bc.oldvexpand = gtk_widget_get_vexpand(widget); - bc.oldvalign = gtk_widget_get_valign(widget); - - if (bc.stretchy) { - if (b->vertical) { - gtk_widget_set_vexpand(widget, TRUE); - gtk_widget_set_valign(widget, GTK_ALIGN_FILL); - } else { - gtk_widget_set_hexpand(widget, TRUE); - gtk_widget_set_halign(widget, GTK_ALIGN_FILL); - } - gtk_size_group_add_widget(b->stretchygroup, widget); - } else - if (b->vertical) - gtk_widget_set_vexpand(widget, FALSE); - else - gtk_widget_set_hexpand(widget, FALSE); - // and make them fill the opposite direction - if (b->vertical) { - gtk_widget_set_hexpand(widget, TRUE); - gtk_widget_set_halign(widget, GTK_ALIGN_FILL); - } else { - gtk_widget_set_vexpand(widget, TRUE); - gtk_widget_set_valign(widget, GTK_ALIGN_FILL); - } - - uiControlSetParent(bc.c, uiControl(b)); - uiUnixControlSetContainer(uiUnixControl(bc.c), b->container, FALSE); - g_array_append_val(b->controls, bc); -} - -void uiBoxDelete(uiBox *b, int index) -{ - struct boxChild *bc; - GtkWidget *widget; - - bc = ctrl(b, index); - widget = GTK_WIDGET(uiControlHandle(bc->c)); - - uiControlSetParent(bc->c, NULL); - uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE); - - if (bc->stretchy) - gtk_size_group_remove_widget(b->stretchygroup, widget); - gtk_widget_set_hexpand(widget, bc->oldhexpand); - gtk_widget_set_halign(widget, bc->oldhalign); - gtk_widget_set_vexpand(widget, bc->oldvexpand); - gtk_widget_set_valign(widget, bc->oldvalign); - - g_array_remove_index(b->controls, index); -} - -int uiBoxPadded(uiBox *b) -{ - return b->padded; -} - -void uiBoxSetPadded(uiBox *b, int padded) -{ - b->padded = padded; - if (b->padded) - if (b->vertical) - gtk_box_set_spacing(b->box, gtkYPadding); - else - gtk_box_set_spacing(b->box, gtkXPadding); - else - gtk_box_set_spacing(b->box, 0); -} - -static uiBox *finishNewBox(GtkOrientation orientation) -{ - uiBox *b; - - uiUnixNewControl(uiBox, b); - - b->widget = gtk_box_new(orientation, 0); - b->container = GTK_CONTAINER(b->widget); - b->box = GTK_BOX(b->widget); - - b->vertical = orientation == GTK_ORIENTATION_VERTICAL; - - if (b->vertical) - b->stretchygroup = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL); - else - b->stretchygroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - - b->controls = g_array_new(FALSE, TRUE, sizeof (struct boxChild)); - - return b; -} - -uiBox *uiNewHorizontalBox(void) -{ - return finishNewBox(GTK_ORIENTATION_HORIZONTAL); -} - -uiBox *uiNewVerticalBox(void) -{ - return finishNewBox(GTK_ORIENTATION_VERTICAL); -} diff --git a/deps/libui/unix/button.c b/deps/libui/unix/button.c deleted file mode 100644 index 00a87f491a..0000000000 --- a/deps/libui/unix/button.c +++ /dev/null @@ -1,55 +0,0 @@ -// 10 june 2015 -#include "uipriv_unix.h" - -struct uiButton { - uiUnixControl c; - GtkWidget *widget; - GtkButton *button; - void (*onClicked)(uiButton *, void *); - void *onClickedData; -}; - -uiUnixControlAllDefaults(uiButton) - -static void onClicked(GtkButton *button, gpointer data) -{ - uiButton *b = uiButton(data); - - (*(b->onClicked))(b, b->onClickedData); -} - -static void defaultOnClicked(uiButton *b, void *data) -{ - // do nothing -} - -char *uiButtonText(uiButton *b) -{ - return uiUnixStrdupText(gtk_button_get_label(b->button)); -} - -void uiButtonSetText(uiButton *b, const char *text) -{ - gtk_button_set_label(b->button, text); -} - -void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *, void *), void *data) -{ - b->onClicked = f; - b->onClickedData = data; -} - -uiButton *uiNewButton(const char *text) -{ - uiButton *b; - - uiUnixNewControl(uiButton, b); - - b->widget = gtk_button_new_with_label(text); - b->button = GTK_BUTTON(b->widget); - - g_signal_connect(b->widget, "clicked", G_CALLBACK(onClicked), b); - uiButtonOnClicked(b, defaultOnClicked, NULL); - - return b; -} diff --git a/deps/libui/unix/cellrendererbutton.c b/deps/libui/unix/cellrendererbutton.c deleted file mode 100644 index e3bbf48b7c..0000000000 --- a/deps/libui/unix/cellrendererbutton.c +++ /dev/null @@ -1,299 +0,0 @@ -// 28 june 2016 -#include "uipriv_unix.h" - -// TODOs -// - it's a rather tight fit -// - selected row text color is white -// - resizing a column with a button in it crashes the program -// - accessibility -// - right side too big? - -#define cellRendererButtonType (cellRendererButton_get_type()) -#define cellRendererButton(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), cellRendererButtonType, cellRendererButton)) -#define isCellRendererButton(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), cellRendererButtonType)) -#define cellRendererButtonClass(class) (G_TYPE_CHECK_CLASS_CAST((class), cellRendererButtonType, cellRendererButtonClass)) -#define isCellRendererButtonClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), cellRendererButton)) -#define getCellRendererButtonClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), cellRendererButtonType, cellRendererButtonClass)) - -typedef struct cellRendererButton cellRendererButton; -typedef struct cellRendererButtonClass cellRendererButtonClass; - -struct cellRendererButton { - GtkCellRenderer parent_instance; - char *text; -}; - -struct cellRendererButtonClass { - GtkCellRendererClass parent_class; -}; - -G_DEFINE_TYPE(cellRendererButton, cellRendererButton, GTK_TYPE_CELL_RENDERER) - -static void cellRendererButton_init(cellRendererButton *c) -{ - g_object_set(c, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); - // the standard cell renderers all do this - gtk_cell_renderer_set_padding(GTK_CELL_RENDERER(c), 2, 2); -} - -static void cellRendererButton_dispose(GObject *obj) -{ - G_OBJECT_CLASS(cellRendererButton_parent_class)->dispose(obj); -} - -static void cellRendererButton_finalize(GObject *obj) -{ - cellRendererButton *c = cellRendererButton(obj); - - if (c->text != NULL) { - g_free(c->text); - c->text = NULL; - } - G_OBJECT_CLASS(cellRendererButton_parent_class)->finalize(obj); -} - -static GtkSizeRequestMode cellRendererButton_get_request_mode(GtkCellRenderer *r) -{ - return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; -} - -// this is basically what GtkCellRendererToggle did in 3.10 and does in 3.20, as well as what the Foreign Drawing gtk3-demo demo does -static GtkStyleContext *setButtonStyle(GtkWidget *widget) -{ - GtkStyleContext *base, *context; - GtkWidgetPath *path; - - base = gtk_widget_get_style_context(widget); - context = gtk_style_context_new(); - - path = gtk_widget_path_copy(gtk_style_context_get_path(base)); - gtk_widget_path_append_type(path, G_TYPE_NONE); - if (!FUTURE_gtk_widget_path_iter_set_object_name(path, -1, "button")) - // not on 3.20; try the type - gtk_widget_path_iter_set_object_type(path, -1, GTK_TYPE_BUTTON); - - gtk_style_context_set_path(context, path); - gtk_style_context_set_parent(context, base); - // the gtk3-demo example (which says we need to do this) uses gtk_widget_path_iter_get_state(path, -1) but that's not available until 3.14 - // TODO make a future for that too - gtk_style_context_set_state(context, gtk_style_context_get_state(base)); - gtk_widget_path_unref(path); - - // and if the above widget path screwery stil doesn't work, this will - gtk_style_context_add_class(context, GTK_STYLE_CLASS_BUTTON); - - return context; -} - -void unsetButtonStyle(GtkStyleContext *context) -{ - g_object_unref(context); -} - -// this is based on what GtkCellRendererText does -static void cellRendererButton_get_preferred_width(GtkCellRenderer *r, GtkWidget *widget, gint *minimum, gint *natural) -{ - cellRendererButton *c = cellRendererButton(r); - gint xpad; - PangoLayout *layout; - PangoRectangle rect; - gint out; - - gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, NULL); - - layout = gtk_widget_create_pango_layout(widget, c->text); - pango_layout_set_width(layout, -1); - pango_layout_get_extents(layout, NULL, &rect); - g_object_unref(layout); - - out = 2 * xpad + PANGO_PIXELS_CEIL(rect.width); - if (minimum != NULL) - *minimum = out; - if (natural != NULL) - *natural = out; -} - -// this is based on what GtkCellRendererText does -static void cellRendererButton_get_preferred_height_for_width(GtkCellRenderer *r, GtkWidget *widget, gint width, gint *minimum, gint *natural) -{ - cellRendererButton *c = cellRendererButton(r); - gint xpad, ypad; - PangoLayout *layout; - gint height; - gint out; - - gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad); - - layout = gtk_widget_create_pango_layout(widget, c->text); - pango_layout_set_width(layout, ((2 * xpad + width) * PANGO_SCALE)); - pango_layout_get_pixel_size(layout, NULL, &height); - g_object_unref(layout); - - out = 2 * ypad + height; - if (minimum != NULL) - *minimum = out; - if (natural != NULL) - *natural = out; -} - -// this is basically what GtkCellRendererText does -static void cellRendererButton_get_preferred_height(GtkCellRenderer *r, GtkWidget *widget, gint *minimum, gint *natural) -{ - gint width; - - gtk_cell_renderer_get_preferred_width(r, widget, &width, NULL); - gtk_cell_renderer_get_preferred_height_for_width(r, widget, width, minimum, natural); -} - -// this is based on what GtkCellRendererText does -static void cellRendererButton_get_aligned_area(GtkCellRenderer *r, GtkWidget *widget, GtkCellRendererState flags, const GdkRectangle *cell_area, GdkRectangle *aligned_area) -{ - cellRendererButton *c = cellRendererButton(r); - gint xpad, ypad; - PangoLayout *layout; - PangoRectangle rect; - gfloat xalign, yalign; - gint xoffset, yoffset; - - gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad); - - layout = gtk_widget_create_pango_layout(widget, c->text); - pango_layout_set_width(layout, -1); - pango_layout_get_pixel_extents(layout, NULL, &rect); - - xoffset = 0; - yoffset = 0; - if (cell_area != NULL) { - gtk_cell_renderer_get_alignment(GTK_CELL_RENDERER(c), &xalign, &yalign); - xoffset = cell_area->width - (2 * xpad + rect.width); - // use explicit casts just to be safe - if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL) - xoffset = ((gdouble) xoffset) * (1.0 - xalign); - else - xoffset *= ((gdouble) xoffset) * xalign; - yoffset = yalign * (cell_area->height - (2 * ypad + rect.height)); - yoffset = MAX(yoffset, 0); - } - - aligned_area->x = cell_area->x + xoffset; - aligned_area->y = cell_area->y + yoffset; - aligned_area->width = 2 * xpad + rect.width; - aligned_area->height = 2 * ypad + rect.height; - - g_object_unref(layout); -} - -// this is based on both what GtkCellRendererText does and what GtkCellRendererToggle does -static void cellRendererButton_render(GtkCellRenderer *r, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags) -{ - cellRendererButton *c = cellRendererButton(r); - gint xpad, ypad; - GdkRectangle alignedArea; - gint xoffset, yoffset; - GtkStyleContext *context; - PangoLayout *layout; - PangoRectangle rect; - - gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad); - gtk_cell_renderer_get_aligned_area(GTK_CELL_RENDERER(c), widget, flags, cell_area, &alignedArea); - xoffset = alignedArea.x - cell_area->x; - yoffset = alignedArea.y - cell_area->y; - - context = setButtonStyle(widget); - layout = gtk_widget_create_pango_layout(widget, c->text); - - gtk_render_background(context, cr, - background_area->x + xoffset + xpad, - background_area->y + yoffset + ypad, - background_area->width - 2 * xpad, - background_area->height - 2 * ypad); - gtk_render_frame(context, cr, - background_area->x + xoffset + xpad, - background_area->y + yoffset + ypad, - background_area->width - 2 * xpad, - background_area->height - 2 * ypad); - - pango_layout_set_width(layout, -1); - pango_layout_get_pixel_extents(layout, NULL, &rect); - xoffset -= rect.x; - gtk_render_layout(context, cr, - cell_area->x + xoffset + xpad, - cell_area->y + yoffset + ypad, - layout); - - g_object_unref(layout); - unsetButtonStyle(context); -} - -static guint clickedSignal; - -static gboolean cellRendererButton_activate(GtkCellRenderer *r, GdkEvent *e, GtkWidget *widget, const gchar *path, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags) -{ - g_signal_emit(r, clickedSignal, 0, path); - return TRUE; -} - -static GParamSpec *props[2] = { NULL, NULL }; - -static void cellRendererButton_set_property(GObject *object, guint prop, const GValue *value, GParamSpec *pspec) -{ - cellRendererButton *c = cellRendererButton(object); - - if (prop != 1) { - G_OBJECT_WARN_INVALID_PROPERTY_ID(c, prop, pspec); - return; - } - if (c->text != NULL) - g_free(c->text); - c->text = g_value_dup_string(value); - // GtkCellRendererText doesn't queue a redraw; we won't either -} - -static void cellRendererButton_get_property(GObject *object, guint prop, GValue *value, GParamSpec *pspec) -{ - cellRendererButton *c = cellRendererButton(object); - - if (prop != 1) { - G_OBJECT_WARN_INVALID_PROPERTY_ID(c, prop, pspec); - return; - } - g_value_set_string(value, c->text); -} - -static void cellRendererButton_class_init(cellRendererButtonClass *class) -{ - G_OBJECT_CLASS(class)->dispose = cellRendererButton_dispose; - G_OBJECT_CLASS(class)->finalize = cellRendererButton_finalize; - G_OBJECT_CLASS(class)->set_property = cellRendererButton_set_property; - G_OBJECT_CLASS(class)->get_property = cellRendererButton_get_property; - GTK_CELL_RENDERER_CLASS(class)->get_request_mode = cellRendererButton_get_request_mode; - GTK_CELL_RENDERER_CLASS(class)->get_preferred_width = cellRendererButton_get_preferred_width; - GTK_CELL_RENDERER_CLASS(class)->get_preferred_height_for_width = cellRendererButton_get_preferred_height_for_width; - GTK_CELL_RENDERER_CLASS(class)->get_preferred_height = cellRendererButton_get_preferred_height; - // don't provide a get_preferred_width_for_height() - GTK_CELL_RENDERER_CLASS(class)->get_aligned_area = cellRendererButton_get_aligned_area; - // don't provide a get_size() - GTK_CELL_RENDERER_CLASS(class)->render = cellRendererButton_render; - GTK_CELL_RENDERER_CLASS(class)->activate = cellRendererButton_activate; - // don't provide a start_editing() - - props[1] = g_param_spec_string("text", - "Text", - "Button text", - "", - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - g_object_class_install_properties(G_OBJECT_CLASS(class), 2, props); - - clickedSignal = g_signal_new("clicked", - G_TYPE_FROM_CLASS(class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, - 1, G_TYPE_STRING); -} - -GtkCellRenderer *newCellRendererButton(void) -{ - return GTK_CELL_RENDERER(g_object_new(cellRendererButtonType, NULL)); -} diff --git a/deps/libui/unix/checkbox.c b/deps/libui/unix/checkbox.c deleted file mode 100644 index 47f851456a..0000000000 --- a/deps/libui/unix/checkbox.c +++ /dev/null @@ -1,78 +0,0 @@ -// 10 june 2015 -#include "uipriv_unix.h" - -struct uiCheckbox { - uiUnixControl c; - GtkWidget *widget; - GtkButton *button; - GtkToggleButton *toggleButton; - GtkCheckButton *checkButton; - void (*onToggled)(uiCheckbox *, void *); - void *onToggledData; - gulong onToggledSignal; -}; - -uiUnixControlAllDefaults(uiCheckbox) - -static void onToggled(GtkToggleButton *b, gpointer data) -{ - uiCheckbox *c = uiCheckbox(data); - - (*(c->onToggled))(c, c->onToggledData); -} - -static void defaultOnToggled(uiCheckbox *c, void *data) -{ - // do nothing -} - -char *uiCheckboxText(uiCheckbox *c) -{ - return uiUnixStrdupText(gtk_button_get_label(c->button)); -} - -void uiCheckboxSetText(uiCheckbox *c, const char *text) -{ - gtk_button_set_label(GTK_BUTTON(c->button), text); -} - -void uiCheckboxOnToggled(uiCheckbox *c, void (*f)(uiCheckbox *, void *), void *data) -{ - c->onToggled = f; - c->onToggledData = data; -} - -int uiCheckboxChecked(uiCheckbox *c) -{ - return gtk_toggle_button_get_active(c->toggleButton) != FALSE; -} - -void uiCheckboxSetChecked(uiCheckbox *c, int checked) -{ - gboolean active; - - active = FALSE; - if (checked) - active = TRUE; - // we need to inhibit sending of ::toggled because this WILL send a ::toggled otherwise - g_signal_handler_block(c->toggleButton, c->onToggledSignal); - gtk_toggle_button_set_active(c->toggleButton, active); - g_signal_handler_unblock(c->toggleButton, c->onToggledSignal); -} - -uiCheckbox *uiNewCheckbox(const char *text) -{ - uiCheckbox *c; - - uiUnixNewControl(uiCheckbox, c); - - c->widget = gtk_check_button_new_with_label(text); - c->button = GTK_BUTTON(c->widget); - c->toggleButton = GTK_TOGGLE_BUTTON(c->widget); - c->checkButton = GTK_CHECK_BUTTON(c->widget); - - c->onToggledSignal = g_signal_connect(c->widget, "toggled", G_CALLBACK(onToggled), c); - uiCheckboxOnToggled(c, defaultOnToggled, NULL); - - return c; -} diff --git a/deps/libui/unix/child.c b/deps/libui/unix/child.c deleted file mode 100644 index b4a0967740..0000000000 --- a/deps/libui/unix/child.c +++ /dev/null @@ -1,120 +0,0 @@ -// 28 august 2015 -#include "uipriv_unix.h" - -// This file contains helpers for managing child controls. - -struct child { - uiControl *c; - GtkWidget *widget; - - gboolean oldhexpand; - GtkAlign oldhalign; - gboolean oldvexpand; - GtkAlign oldvalign; - - // Some children can be boxed; that is, they can have an optionally-margined box around them. - // uiGroup, uiTab, and uiWindow all do this. - GtkWidget *box; - - // If the child is not boxed, this is its parent. - // If the child is boxed, this is the box. - GtkContainer *parent; - - // This flag is for users of these functions. - // For uiBox, this is "spaced". - // For uiTab, this is "margined". (uiGroup and uiWindow have to maintain their margined state themselves, since the margined state is independent of whether there is a child for those two.) - int flag; -}; - -struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parentContainer) -{ - struct child *c; - - if (child == NULL) - return NULL; - - c = uiNew(struct child); - c->c = child; - c->widget = GTK_WIDGET(uiControlHandle(c->c)); - - c->oldhexpand = gtk_widget_get_hexpand(c->widget); - c->oldhalign = gtk_widget_get_halign(c->widget); - c->oldvexpand = gtk_widget_get_vexpand(c->widget); - c->oldvalign = gtk_widget_get_valign(c->widget); - - uiControlSetParent(c->c, parent); - uiUnixControlSetContainer(uiUnixControl(c->c), parentContainer, FALSE); - c->parent = parentContainer; - - return c; -} - -struct child *newChildWithBox(uiControl *child, uiControl *parent, GtkContainer *parentContainer, int margined) -{ - struct child *c; - GtkWidget *box; - - if (child == NULL) - return NULL; - box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_widget_show(box); - c = newChild(child, parent, GTK_CONTAINER(box)); - gtk_widget_set_hexpand(c->widget, TRUE); - gtk_widget_set_halign(c->widget, GTK_ALIGN_FILL); - gtk_widget_set_vexpand(c->widget, TRUE); - gtk_widget_set_valign(c->widget, GTK_ALIGN_FILL); - c->box = box; - gtk_container_add(parentContainer, c->box); - childSetMargined(c, margined); - return c; -} - -void childRemove(struct child *c) -{ - uiControlSetParent(c->c, NULL); - uiUnixControlSetContainer(uiUnixControl(c->c), c->parent, TRUE); - - gtk_widget_set_hexpand(c->widget, c->oldhexpand); - gtk_widget_set_halign(c->widget, c->oldhalign); - gtk_widget_set_vexpand(c->widget, c->oldvexpand); - gtk_widget_set_valign(c->widget, c->oldvalign); - - if (c->box != NULL) - gtk_widget_destroy(c->box); - - uiFree(c); -} - -void childDestroy(struct child *c) -{ - uiControl *child; - - child = c->c; - childRemove(c); - uiControlDestroy(child); -} - -GtkWidget *childWidget(struct child *c) -{ - return c->widget; -} - -int childFlag(struct child *c) -{ - return c->flag; -} - -void childSetFlag(struct child *c, int flag) -{ - c->flag = flag; -} - -GtkWidget *childBox(struct child *c) -{ - return c->box; -} - -void childSetMargined(struct child *c, int margined) -{ - setMargined(GTK_CONTAINER(c->box), margined); -} diff --git a/deps/libui/unix/colorbutton.c b/deps/libui/unix/colorbutton.c deleted file mode 100644 index 393b16f1d3..0000000000 --- a/deps/libui/unix/colorbutton.c +++ /dev/null @@ -1,80 +0,0 @@ -// 15 may 2016 -#include "uipriv_unix.h" - -struct uiColorButton { - uiUnixControl c; - GtkWidget *widget; - GtkButton *button; - GtkColorButton *cb; - GtkColorChooser *cc; - void (*onChanged)(uiColorButton *, void *); - void *onChangedData; -}; - -uiUnixControlAllDefaults(uiColorButton) - -static void onColorSet(GtkColorButton *button, gpointer data) -{ - uiColorButton *b = uiColorButton(data); - - (*(b->onChanged))(b, b->onChangedData); -} - -static void defaultOnChanged(uiColorButton *b, void *data) -{ - // do nothing -} - -void uiColorButtonColor(uiColorButton *b, double *r, double *g, double *bl, double *a) -{ - GdkRGBA rgba; - - gtk_color_chooser_get_rgba(b->cc, &rgba); - *r = rgba.red; - *g = rgba.green; - *bl = rgba.blue; - *a = rgba.alpha; -} - -void uiColorButtonSetColor(uiColorButton *b, double r, double g, double bl, double a) -{ - GdkRGBA rgba; - - rgba.red = r; - rgba.green = g; - rgba.blue = bl; - rgba.alpha = a; - // no need to inhibit the signal; color-set is documented as only being sent when the user changes the color - gtk_color_chooser_set_rgba(b->cc, &rgba); -} - -void uiColorButtonOnChanged(uiColorButton *b, void (*f)(uiColorButton *, void *), void *data) -{ - b->onChanged = f; - b->onChangedData = data; -} - -uiColorButton *uiNewColorButton(void) -{ - uiColorButton *b; - GdkRGBA black; - - uiUnixNewControl(uiColorButton, b); - - // I'm not sure what the initial color is; set up a real one - black.red = 0.0; - black.green = 0.0; - black.blue = 0.0; - black.alpha = 1.0; - b->widget = gtk_color_button_new_with_rgba(&black); - b->button = GTK_BUTTON(b->widget); - b->cb = GTK_COLOR_BUTTON(b->widget); - b->cc = GTK_COLOR_CHOOSER(b->widget); - - gtk_color_chooser_set_use_alpha(b->cc, TRUE); - - g_signal_connect(b->widget, "color-set", G_CALLBACK(onColorSet), b); - uiColorButtonOnChanged(b, defaultOnChanged, NULL); - - return b; -} diff --git a/deps/libui/unix/combobox.c b/deps/libui/unix/combobox.c deleted file mode 100644 index 6fed804bb1..0000000000 --- a/deps/libui/unix/combobox.c +++ /dev/null @@ -1,66 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiCombobox { - uiUnixControl c; - GtkWidget *widget; - GtkComboBox *combobox; - GtkComboBoxText *comboboxText; - void (*onSelected)(uiCombobox *, void *); - void *onSelectedData; - gulong onSelectedSignal; -}; - -uiUnixControlAllDefaults(uiCombobox) - -static void onChanged(GtkComboBox *cbox, gpointer data) -{ - uiCombobox *c = uiCombobox(data); - - (*(c->onSelected))(c, c->onSelectedData); -} - -static void defaultOnSelected(uiCombobox *c, void *data) -{ - // do nothing -} - -void uiComboboxAppend(uiCombobox *c, const char *text) -{ - gtk_combo_box_text_append(c->comboboxText, NULL, text); -} - -int uiComboboxSelected(uiCombobox *c) -{ - return gtk_combo_box_get_active(c->combobox); -} - -void uiComboboxSetSelected(uiCombobox *c, int n) -{ - // we need to inhibit sending of ::changed because this WILL send a ::changed otherwise - g_signal_handler_block(c->combobox, c->onSelectedSignal); - gtk_combo_box_set_active(c->combobox, n); - g_signal_handler_unblock(c->combobox, c->onSelectedSignal); -} - -void uiComboboxOnSelected(uiCombobox *c, void (*f)(uiCombobox *c, void *data), void *data) -{ - c->onSelected = f; - c->onSelectedData = data; -} - -uiCombobox *uiNewCombobox(void) -{ - uiCombobox *c; - - uiUnixNewControl(uiCombobox, c); - - c->widget = gtk_combo_box_text_new(); - c->combobox = GTK_COMBO_BOX(c->widget); - c->comboboxText = GTK_COMBO_BOX_TEXT(c->widget); - - c->onSelectedSignal = g_signal_connect(c->widget, "changed", G_CALLBACK(onChanged), c); - uiComboboxOnSelected(c, defaultOnSelected, NULL); - - return c; -} diff --git a/deps/libui/unix/control.c b/deps/libui/unix/control.c deleted file mode 100644 index f6fdcea2a3..0000000000 --- a/deps/libui/unix/control.c +++ /dev/null @@ -1,14 +0,0 @@ -// 16 august 2015 -#include "uipriv_unix.h" - -void uiUnixControlSetContainer(uiUnixControl *c, GtkContainer *container, gboolean remove) -{ - (*(c->SetContainer))(c, container, remove); -} - -#define uiUnixControlSignature 0x556E6978 - -uiUnixControl *uiUnixAllocControl(size_t n, uint32_t typesig, const char *typenamestr) -{ - return uiUnixControl(uiAllocControl(n, uiUnixControlSignature, typesig, typenamestr)); -} diff --git a/deps/libui/unix/datetimepicker.c b/deps/libui/unix/datetimepicker.c deleted file mode 100644 index 19689a2205..0000000000 --- a/deps/libui/unix/datetimepicker.c +++ /dev/null @@ -1,599 +0,0 @@ -// 4 september 2015 -#include "uipriv_unix.h" - -// LONGTERM imitate gnome-calendar's day/month/year entries above the calendar -// LONGTERM allow entering a 24-hour hour in the hour spinbutton and adjust accordingly - -#define dateTimePickerWidgetType (dateTimePickerWidget_get_type()) -#define dateTimePickerWidget(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), dateTimePickerWidgetType, dateTimePickerWidget)) -#define isDateTimePickerWidget(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), dateTimePickerWidgetType)) -#define dateTimePickerWidgetClass(class) (G_TYPE_CHECK_CLASS_CAST((class), dateTimePickerWidgetType, dateTimePickerWidgetClass)) -#define isDateTimePickerWidgetClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), dateTimePickerWidget)) -#define getDateTimePickerWidgetClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), dateTimePickerWidgetType, dateTimePickerWidgetClass)) - -typedef struct dateTimePickerWidget dateTimePickerWidget; -typedef struct dateTimePickerWidgetClass dateTimePickerWidgetClass; - -struct dateTimePickerWidget { - GtkToggleButton parent_instance; - - gulong toggledSignal; - - gboolean hasTime; - gboolean hasDate; - - GtkWidget *window; - GtkWidget *box; - GtkWidget *calendar; - GtkWidget *timebox; - GtkWidget *hours; - GtkWidget *minutes; - GtkWidget *seconds; - GtkWidget *ampm; - - gulong hoursBlock; - gulong minutesBlock; - gulong secondsBlock; - gulong ampmBlock; - - GdkDevice *keyboard; - GdkDevice *mouse; -}; - -struct dateTimePickerWidgetClass { - GtkToggleButtonClass parent_class; -}; - -G_DEFINE_TYPE(dateTimePickerWidget, dateTimePickerWidget, GTK_TYPE_TOGGLE_BUTTON) - -static int realSpinValue(GtkSpinButton *spinButton) -{ - GtkAdjustment *adj; - - adj = gtk_spin_button_get_adjustment(spinButton); - return (int) gtk_adjustment_get_value(adj); -} - -static void setRealSpinValue(GtkSpinButton *spinButton, int value, gulong block) -{ - GtkAdjustment *adj; - - g_signal_handler_block(spinButton, block); - adj = gtk_spin_button_get_adjustment(spinButton); - gtk_adjustment_set_value(adj, value); - g_signal_handler_unblock(spinButton, block); -} - -static GDateTime *selected(dateTimePickerWidget *d) -{ - // choose a day for which all times are likely to be valid for the default date in case we're only dealing with time - guint year = 1970, month = 1, day = 1; - guint hour = 0, minute = 0, second = 0; - - if (d->hasDate) { - gtk_calendar_get_date(GTK_CALENDAR(d->calendar), &year, &month, &day); - month++; // GtkCalendar/GDateTime differences - } - if (d->hasTime) { - hour = realSpinValue(GTK_SPIN_BUTTON(d->hours)); - if (realSpinValue(GTK_SPIN_BUTTON(d->ampm)) != 0) - hour += 12; - minute = realSpinValue(GTK_SPIN_BUTTON(d->minutes)); - second = realSpinValue(GTK_SPIN_BUTTON(d->seconds)); - } - return g_date_time_new_local(year, month, day, hour, minute, second); -} - -static void setLabel(dateTimePickerWidget *d) -{ - GDateTime *dt; - char *fmt; - char *msg; - gboolean free; - - dt = selected(d); - free = FALSE; - if (d->hasDate && d->hasTime) { - // don't use D_T_FMT; that's too verbose - fmt = g_strdup_printf("%s %s", nl_langinfo(D_FMT), nl_langinfo(T_FMT)); - free = TRUE; - } else if (d->hasDate) - fmt = nl_langinfo(D_FMT); - else - fmt = nl_langinfo(T_FMT); - msg = g_date_time_format(dt, fmt); - gtk_button_set_label(GTK_BUTTON(d), msg); - g_free(msg); - if (free) - g_free(fmt); - g_date_time_unref(dt); -} - -static void dateTimeChanged(dateTimePickerWidget *d) -{ - setLabel(d); - // TODO fire event here -} - -// we don't want ::toggled to be sent again -static void setActive(dateTimePickerWidget *d, gboolean active) -{ - g_signal_handler_block(d, d->toggledSignal); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d), active); - g_signal_handler_unblock(d, d->toggledSignal); -} - -// like startGrab() below, a lot of this is in the order that GtkComboBox does it -static void endGrab(dateTimePickerWidget *d) -{ - if (d->keyboard != NULL) - gdk_device_ungrab(d->keyboard, GDK_CURRENT_TIME); - gdk_device_ungrab(d->mouse, GDK_CURRENT_TIME); - gtk_device_grab_remove(d->window, d->mouse); - d->keyboard = NULL; - d->mouse = NULL; -} - -static void hidePopup(dateTimePickerWidget *d) -{ - endGrab(d); - gtk_widget_hide(d->window); - setActive(d, FALSE); -} - -// this consolidates a good chunk of what GtkComboBox does -static gboolean startGrab(dateTimePickerWidget *d) -{ - GdkDevice *dev; - guint32 time; - GdkWindow *window; - GdkDevice *keyboard, *mouse; - - dev = gtk_get_current_event_device(); - if (dev == NULL) { - // this is what GtkComboBox does - // since no device was set, just use the first available "master device" - GdkDisplay *disp; - GdkDeviceManager *dm; - GList *list; - - disp = gtk_widget_get_display(GTK_WIDGET(d)); - dm = gdk_display_get_device_manager(disp); - list = gdk_device_manager_list_devices(dm, GDK_DEVICE_TYPE_MASTER); - dev = (GdkDevice *) (list->data); - g_list_free(list); - } - - time = gtk_get_current_event_time(); - keyboard = dev; - mouse = gdk_device_get_associated_device(dev); - if (gdk_device_get_source(dev) != GDK_SOURCE_KEYBOARD) { - dev = mouse; - mouse = keyboard; - keyboard = dev; - } - - window = gtk_widget_get_window(d->window); - if (keyboard != NULL) - if (gdk_device_grab(keyboard, window, - GDK_OWNERSHIP_WINDOW, TRUE, - GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, - NULL, time) != GDK_GRAB_SUCCESS) - return FALSE; - if (mouse != NULL) - if (gdk_device_grab(mouse, window, - GDK_OWNERSHIP_WINDOW, TRUE, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK, - NULL, time) != GDK_GRAB_SUCCESS) { - if (keyboard != NULL) - gdk_device_ungrab(keyboard, time); - return FALSE; - } - - gtk_device_grab_add(d->window, mouse, TRUE); - d->keyboard = keyboard; - d->mouse = mouse; - return TRUE; -} - -// based on gtk_combo_box_list_position() in the GTK+ source code -static void allocationToScreen(dateTimePickerWidget *d, gint *x, gint *y) -{ - GdkWindow *window; - GtkAllocation a; - GtkRequisition aWin; - GdkScreen *screen; - GdkRectangle workarea; - int otherY; - - gtk_widget_get_allocation(GTK_WIDGET(d), &a); - gtk_widget_get_preferred_size(d->window, &aWin, NULL); - *x = 0; - *y = 0; - if (!gtk_widget_get_has_window(GTK_WIDGET(d))) { - *x = a.x; - *y = a.y; - } - window = gtk_widget_get_window(GTK_WIDGET(d)); - gdk_window_get_root_coords(window, *x, *y, x, y); - if (gtk_widget_get_direction(GTK_WIDGET(d)) == GTK_TEXT_DIR_RTL) - *x += a.width - aWin.width; - - // now adjust to prevent the box from going offscreen - screen = gtk_widget_get_screen(GTK_WIDGET(d)); - gdk_screen_get_monitor_workarea(screen, - gdk_screen_get_monitor_at_window(screen, window), - &workarea); - if (*x < workarea.x) // too far to the left? - *x = workarea.x; - else if (*x + aWin.width > (workarea.x + workarea.width)) // too far to the right? - *x = (workarea.x + workarea.width) - aWin.width; - // this isn't the same algorithm used by GtkComboBox - // first, get our two choices; *y for down and otherY for up - otherY = *y - aWin.height; - *y += a.height; - // and use otherY if we're too low - if (*y + aWin.height >= workarea.y + workarea.height) - *y = otherY; -} - -static void showPopup(dateTimePickerWidget *d) -{ - GtkWidget *toplevel; - gint x, y; - - // GtkComboBox does it - toplevel = gtk_widget_get_toplevel(GTK_WIDGET(d)); - if (GTK_IS_WINDOW(toplevel)) - gtk_window_group_add_window(gtk_window_get_group(GTK_WINDOW(toplevel)), GTK_WINDOW(d->window)); - - allocationToScreen(d, &x, &y); - gtk_window_move(GTK_WINDOW(d->window), x, y); - - gtk_widget_show(d->window); - setActive(d, TRUE); - - if (!startGrab(d)) - hidePopup(d); -} - -static void onToggled(GtkToggleButton *b, gpointer data) -{ - dateTimePickerWidget *d = dateTimePickerWidget(b); - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d))) - showPopup(d); - else - hidePopup(d); -} - -static gboolean grabBroken(GtkWidget *w, GdkEventGrabBroken *e, gpointer data) -{ - dateTimePickerWidget *d = dateTimePickerWidget(data); - - hidePopup(d); - return TRUE; // this is what GtkComboBox does -} - -static gboolean buttonReleased(GtkWidget *w, GdkEventButton *e, gpointer data) -{ - dateTimePickerWidget *d = dateTimePickerWidget(data); - int winx, winy; - GtkAllocation wina; - gboolean in; - - gtk_widget_get_allocation(d->window, &wina); - winx = 0; - winy = 0; - if (!gtk_widget_get_has_window(d->window)) { - winx = wina.x; - winy = wina.y; - } - gdk_window_get_root_coords(gtk_widget_get_window(d->window), winx, winy, &winx, &winy); - in = TRUE; - if (e->x_root < winx) - in = FALSE; - if (e->x_root >= (winx + wina.width)) - in = FALSE; - if (e->y_root < winy) - in = FALSE; - if (e->y_root >= (winy + wina.height)) - in = FALSE; - if (!in) - hidePopup(d); - return TRUE; // this is what GtkComboBox does -} - -static gint hoursSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data) -{ - double *out = (double *) ptr; - const gchar *text; - int value; - - text = gtk_entry_get_text(GTK_ENTRY(sb)); - value = (int) g_strtod(text, NULL); - if (value < 0 || value > 12) - return GTK_INPUT_ERROR; - if (value == 12) // 12 to the user is 0 internally - value = 0; - *out = (double) value; - return TRUE; -} - -static gboolean hoursSpinboxOutput(GtkSpinButton *sb, gpointer data) -{ - gchar *text; - int value; - - value = realSpinValue(sb); - if (value == 0) // 0 internally is 12 to the user - value = 12; - text = g_strdup_printf("%d", value); - gtk_entry_set_text(GTK_ENTRY(sb), text); - g_free(text); - return TRUE; -} - -static gboolean zeroPadSpinbox(GtkSpinButton *sb, gpointer data) -{ - gchar *text; - int value; - - value = realSpinValue(sb); - text = g_strdup_printf("%02d", value); - gtk_entry_set_text(GTK_ENTRY(sb), text); - g_free(text); - return TRUE; -} - -// this is really hacky but we can't use GtkCombobox here :( -static gint ampmSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data) -{ - double *out = (double *) ptr; - const gchar *text; - char firstAM, firstPM; - - text = gtk_entry_get_text(GTK_ENTRY(sb)); - // LONGTERM don't use ASCII here for case insensitivity - firstAM = g_ascii_tolower(nl_langinfo(AM_STR)[0]); - firstPM = g_ascii_tolower(nl_langinfo(PM_STR)[0]); - for (; *text != '\0'; text++) - if (g_ascii_tolower(*text) == firstAM) { - *out = 0; - return TRUE; - } else if (g_ascii_tolower(*text) == firstPM) { - *out = 1; - return TRUE; - } - return GTK_INPUT_ERROR; -} - -static gboolean ampmSpinboxOutput(GtkSpinButton *sb, gpointer data) -{ - int value; - - value = gtk_spin_button_get_value_as_int(sb); - if (value == 0) - gtk_entry_set_text(GTK_ENTRY(sb), nl_langinfo(AM_STR)); - else - gtk_entry_set_text(GTK_ENTRY(sb), nl_langinfo(PM_STR)); - return TRUE; -} - -static void spinboxChanged(GtkSpinButton *sb, gpointer data) -{ - dateTimePickerWidget *d = dateTimePickerWidget(data); - - dateTimeChanged(d); -} - -static GtkWidget *newSpinbox(dateTimePickerWidget *d, int min, int max, gint (*input)(GtkSpinButton *, gpointer, gpointer), gboolean (*output)(GtkSpinButton *, gpointer), gulong *block) -{ - GtkWidget *sb; - - sb = gtk_spin_button_new_with_range(min, max, 1); - gtk_spin_button_set_digits(GTK_SPIN_BUTTON(sb), 0); - gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(sb), TRUE); - gtk_orientable_set_orientation(GTK_ORIENTABLE(sb), GTK_ORIENTATION_VERTICAL); - *block = g_signal_connect(sb, "value-changed", G_CALLBACK(spinboxChanged), d); - if (input != NULL) - g_signal_connect(sb, "input", G_CALLBACK(input), NULL); - if (output != NULL) - g_signal_connect(sb, "output", G_CALLBACK(output), NULL); - return sb; -} - -static void dateChanged(GtkCalendar *c, gpointer data) -{ - dateTimePickerWidget *d = dateTimePickerWidget(data); - - dateTimeChanged(d); -} - -static void setDateOnly(dateTimePickerWidget *d) -{ - d->hasTime = FALSE; - gtk_container_remove(GTK_CONTAINER(d->box), d->timebox); -} - -static void setTimeOnly(dateTimePickerWidget *d) -{ - d->hasDate = FALSE; - gtk_container_remove(GTK_CONTAINER(d->box), d->calendar); -} - -static void dateTimePickerWidget_init(dateTimePickerWidget *d) -{ - GDateTime *dt; - gint year, month, day; - gint hour; - gulong calendarBlock; - - d->window = gtk_window_new(GTK_WINDOW_POPUP); - gtk_window_set_resizable(GTK_WINDOW(d->window), FALSE); - gtk_window_set_attached_to(GTK_WINDOW(d->window), GTK_WIDGET(d)); - gtk_window_set_decorated(GTK_WINDOW(d->window), FALSE); - gtk_window_set_deletable(GTK_WINDOW(d->window), FALSE); - gtk_window_set_type_hint(GTK_WINDOW(d->window), GDK_WINDOW_TYPE_HINT_COMBO); - gtk_window_set_skip_taskbar_hint(GTK_WINDOW(d->window), TRUE); - gtk_window_set_skip_pager_hint(GTK_WINDOW(d->window), TRUE); - gtk_window_set_has_resize_grip(GTK_WINDOW(d->window), FALSE); - gtk_container_set_border_width(GTK_CONTAINER(d->window), 12); - // and make it stand out a bit - gtk_style_context_add_class(gtk_widget_get_style_context(d->window), "frame"); - - d->box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - gtk_container_add(GTK_CONTAINER(d->window), d->box); - - d->calendar = gtk_calendar_new(); - calendarBlock = g_signal_connect(d->calendar, "day-selected", G_CALLBACK(dateChanged), d); - gtk_container_add(GTK_CONTAINER(d->box), d->calendar); - - d->timebox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - gtk_widget_set_valign(d->timebox, GTK_ALIGN_CENTER); - gtk_container_add(GTK_CONTAINER(d->box), d->timebox); - - d->hours = newSpinbox(d, 0, 11, hoursSpinboxInput, hoursSpinboxOutput, &(d->hoursBlock)); - gtk_container_add(GTK_CONTAINER(d->timebox), d->hours); - - gtk_container_add(GTK_CONTAINER(d->timebox), - gtk_label_new(":")); - - d->minutes = newSpinbox(d, 0, 59, NULL, zeroPadSpinbox, &(d->minutesBlock)); - gtk_container_add(GTK_CONTAINER(d->timebox), d->minutes); - - gtk_container_add(GTK_CONTAINER(d->timebox), - gtk_label_new(":")); - - d->seconds = newSpinbox(d, 0, 59, NULL, zeroPadSpinbox, &(d->secondsBlock)); - gtk_container_add(GTK_CONTAINER(d->timebox), d->seconds); - - // LONGTERM this should be the case, but that interferes with grabs - // switch to it when we can drop GTK+ 3.10 and use popovers -#if 0 - d->ampm = gtk_combo_box_text_new(); - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(d->ampm), NULL, "AM"); - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(d->ampm), NULL, "PM"); -#endif - d->ampm = newSpinbox(d, 0, 1, ampmSpinboxInput, ampmSpinboxOutput, &(d->ampmBlock)); - gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(d->ampm), FALSE); - gtk_widget_set_valign(d->ampm, GTK_ALIGN_CENTER); - gtk_container_add(GTK_CONTAINER(d->timebox), d->ampm); - - gtk_widget_show_all(d->box); - - g_signal_connect(d->window, "grab-broken-event", G_CALLBACK(grabBroken), d); - g_signal_connect(d->window, "button-release-event", G_CALLBACK(buttonReleased), d); - - d->toggledSignal = g_signal_connect(d, "toggled", G_CALLBACK(onToggled), NULL); - d->keyboard = NULL; - d->mouse = NULL; - - d->hasTime = TRUE; - d->hasDate = TRUE; - - // set the current date/time - // notice how we block signals from firing - dt = g_date_time_new_now_local(); - g_date_time_get_ymd(dt, &year, &month, &day); - month--; // GDateTime/GtkCalendar differences - g_signal_handler_block(d->calendar, calendarBlock); - gtk_calendar_select_month(GTK_CALENDAR(d->calendar), month, year); - gtk_calendar_select_day(GTK_CALENDAR(d->calendar), day); - g_signal_handler_unblock(d->calendar, calendarBlock); - hour = g_date_time_get_hour(dt); - if (hour >= 12) { - hour -= 12; - setRealSpinValue(GTK_SPIN_BUTTON(d->ampm), 1, d->ampmBlock); - } - setRealSpinValue(GTK_SPIN_BUTTON(d->hours), hour, d->hoursBlock); - setRealSpinValue(GTK_SPIN_BUTTON(d->minutes), g_date_time_get_minute(dt), d->minutesBlock); - setRealSpinValue(GTK_SPIN_BUTTON(d->seconds), g_date_time_get_seconds(dt), d->secondsBlock); - g_date_time_unref(dt); -} - -static void dateTimePickerWidget_dispose(GObject *obj) -{ - dateTimePickerWidget *d = dateTimePickerWidget(obj); - - if (d->window != NULL) { - gtk_widget_destroy(d->window); - d->window = NULL; - } - G_OBJECT_CLASS(dateTimePickerWidget_parent_class)->dispose(obj); -} - -static void dateTimePickerWidget_finalize(GObject *obj) -{ - G_OBJECT_CLASS(dateTimePickerWidget_parent_class)->finalize(obj); -} - -static void dateTimePickerWidget_class_init(dateTimePickerWidgetClass *class) -{ - G_OBJECT_CLASS(class)->dispose = dateTimePickerWidget_dispose; - G_OBJECT_CLASS(class)->finalize = dateTimePickerWidget_finalize; -} - -static GtkWidget *newDTP(void) -{ - GtkWidget *w; - - w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); - setLabel(dateTimePickerWidget(w)); - return w; -} - -static GtkWidget *newDP(void) -{ - GtkWidget *w; - - w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); - setDateOnly(dateTimePickerWidget(w)); - setLabel(dateTimePickerWidget(w)); - return w; -} - -static GtkWidget *newTP(void) -{ - GtkWidget *w; - - w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); - setTimeOnly(dateTimePickerWidget(w)); - setLabel(dateTimePickerWidget(w)); - return w; -} - -struct uiDateTimePicker { - uiUnixControl c; - GtkWidget *widget; - dateTimePickerWidget *d; -}; - -uiUnixControlAllDefaults(uiDateTimePicker) - -uiDateTimePicker *finishNewDateTimePicker(GtkWidget *(*fn)(void)) -{ - uiDateTimePicker *d; - - uiUnixNewControl(uiDateTimePicker, d); - - d->widget = (*fn)(); - d->d = dateTimePickerWidget(d->widget); - - return d; -} - -uiDateTimePicker *uiNewDateTimePicker(void) -{ - return finishNewDateTimePicker(newDTP); -} - -uiDateTimePicker *uiNewDatePicker(void) -{ - return finishNewDateTimePicker(newDP); -} - -uiDateTimePicker *uiNewTimePicker(void) -{ - return finishNewDateTimePicker(newTP); -} diff --git a/deps/libui/unix/debug.c b/deps/libui/unix/debug.c deleted file mode 100644 index c948db6201..0000000000 --- a/deps/libui/unix/debug.c +++ /dev/null @@ -1,14 +0,0 @@ -// 13 may 2016 -#include "uipriv_unix.h" - -// LONGTERM don't halt on release builds - -void realbug(const char *file, const char *line, const char *func, const char *prefix, const char *format, va_list ap) -{ - char *a, *b; - - a = g_strdup_printf("[libui] %s:%s:%s() %s", file, line, func, prefix); - b = g_strdup_vprintf(format, ap); - g_critical("%s%s", a, b); - G_BREAKPOINT(); -} diff --git a/deps/libui/unix/draw.c b/deps/libui/unix/draw.c deleted file mode 100644 index 2d7a6367da..0000000000 --- a/deps/libui/unix/draw.c +++ /dev/null @@ -1,141 +0,0 @@ -// 6 september 2015 -#include "uipriv_unix.h" -#include "draw.h" - -uiDrawContext *newContext(cairo_t *cr) -{ - uiDrawContext *c; - - c = uiNew(uiDrawContext); - c->cr = cr; - return c; -} - -void freeContext(uiDrawContext *c) -{ - uiFree(c); -} - -static cairo_pattern_t *mkbrush(uiDrawBrush *b) -{ - cairo_pattern_t *pat; - size_t i; - - switch (b->Type) { - case uiDrawBrushTypeSolid: - pat = cairo_pattern_create_rgba(b->R, b->G, b->B, b->A); - break; - case uiDrawBrushTypeLinearGradient: - pat = cairo_pattern_create_linear(b->X0, b->Y0, b->X1, b->Y1); - break; - case uiDrawBrushTypeRadialGradient: - // make the start circle radius 0 to make it a point - pat = cairo_pattern_create_radial( - b->X0, b->Y0, 0, - b->X1, b->Y1, b->OuterRadius); - break; -// case uiDrawBrushTypeImage: - } - if (cairo_pattern_status(pat) != CAIRO_STATUS_SUCCESS) - implbug("error creating pattern in mkbrush(): %s", - cairo_status_to_string(cairo_pattern_status(pat))); - switch (b->Type) { - case uiDrawBrushTypeLinearGradient: - case uiDrawBrushTypeRadialGradient: - for (i = 0; i < b->NumStops; i++) - cairo_pattern_add_color_stop_rgba(pat, - b->Stops[i].Pos, - b->Stops[i].R, - b->Stops[i].G, - b->Stops[i].B, - b->Stops[i].A); - } - return pat; -} - -void uiDrawStroke(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b, uiDrawStrokeParams *p) -{ - cairo_pattern_t *pat; - - runPath(path, c->cr); - pat = mkbrush(b); - cairo_set_source(c->cr, pat); - switch (p->Cap) { - case uiDrawLineCapFlat: - cairo_set_line_cap(c->cr, CAIRO_LINE_CAP_BUTT); - break; - case uiDrawLineCapRound: - cairo_set_line_cap(c->cr, CAIRO_LINE_CAP_ROUND); - break; - case uiDrawLineCapSquare: - cairo_set_line_cap(c->cr, CAIRO_LINE_CAP_SQUARE); - break; - } - switch (p->Join) { - case uiDrawLineJoinMiter: - cairo_set_line_join(c->cr, CAIRO_LINE_JOIN_MITER); - cairo_set_miter_limit(c->cr, p->MiterLimit); - break; - case uiDrawLineJoinRound: - cairo_set_line_join(c->cr, CAIRO_LINE_JOIN_ROUND); - break; - case uiDrawLineJoinBevel: - cairo_set_line_join(c->cr, CAIRO_LINE_JOIN_BEVEL); - break; - } - cairo_set_line_width(c->cr, p->Thickness); - cairo_set_dash(c->cr, p->Dashes, p->NumDashes, p->DashPhase); - cairo_stroke(c->cr); - cairo_pattern_destroy(pat); -} - -void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b) -{ - cairo_pattern_t *pat; - - runPath(path, c->cr); - pat = mkbrush(b); - cairo_set_source(c->cr, pat); - switch (pathFillMode(path)) { - case uiDrawFillModeWinding: - cairo_set_fill_rule(c->cr, CAIRO_FILL_RULE_WINDING); - break; - case uiDrawFillModeAlternate: - cairo_set_fill_rule(c->cr, CAIRO_FILL_RULE_EVEN_ODD); - break; - } - cairo_fill(c->cr); - cairo_pattern_destroy(pat); -} - -void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m) -{ - cairo_matrix_t cm; - - m2c(m, &cm); - cairo_transform(c->cr, &cm); -} - -void uiDrawClip(uiDrawContext *c, uiDrawPath *path) -{ - runPath(path, c->cr); - switch (pathFillMode(path)) { - case uiDrawFillModeWinding: - cairo_set_fill_rule(c->cr, CAIRO_FILL_RULE_WINDING); - break; - case uiDrawFillModeAlternate: - cairo_set_fill_rule(c->cr, CAIRO_FILL_RULE_EVEN_ODD); - break; - } - cairo_clip(c->cr); -} - -void uiDrawSave(uiDrawContext *c) -{ - cairo_save(c->cr); -} - -void uiDrawRestore(uiDrawContext *c) -{ - cairo_restore(c->cr); -} diff --git a/deps/libui/unix/draw.h b/deps/libui/unix/draw.h deleted file mode 100644 index dbd82ff565..0000000000 --- a/deps/libui/unix/draw.h +++ /dev/null @@ -1,13 +0,0 @@ -// 5 may 2016 - -// draw.c -struct uiDrawContext { - cairo_t *cr; -}; - -// drawpath.c -extern void runPath(uiDrawPath *p, cairo_t *cr); -extern uiDrawFillMode pathFillMode(uiDrawPath *path); - -// drawmatrix.c -extern void m2c(uiDrawMatrix *m, cairo_matrix_t *c); diff --git a/deps/libui/unix/drawmatrix.c b/deps/libui/unix/drawmatrix.c deleted file mode 100644 index ac7ac579c7..0000000000 --- a/deps/libui/unix/drawmatrix.c +++ /dev/null @@ -1,109 +0,0 @@ -// 6 september 2015 -#include "uipriv_unix.h" -#include "draw.h" - -void m2c(uiDrawMatrix *m, cairo_matrix_t *c) -{ - c->xx = m->M11; - c->yx = m->M12; - c->xy = m->M21; - c->yy = m->M22; - c->x0 = m->M31; - c->y0 = m->M32; -} - -static void c2m(cairo_matrix_t *c, uiDrawMatrix *m) -{ - m->M11 = c->xx; - m->M12 = c->yx; - m->M21 = c->xy; - m->M22 = c->yy; - m->M31 = c->x0; - m->M32 = c->y0; -} - -void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y) -{ - cairo_matrix_t c; - - m2c(m, &c); - cairo_matrix_translate(&c, x, y); - c2m(&c, m); -} - -void uiDrawMatrixScale(uiDrawMatrix *m, double xCenter, double yCenter, double x, double y) -{ - cairo_matrix_t c; - double xt, yt; - - m2c(m, &c); - xt = x; - yt = y; - scaleCenter(xCenter, yCenter, &xt, &yt); - cairo_matrix_translate(&c, xt, yt); - cairo_matrix_scale(&c, x, y); - cairo_matrix_translate(&c, -xt, -yt); - c2m(&c, m); -} - -void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount) -{ - cairo_matrix_t c; - - m2c(m, &c); - cairo_matrix_translate(&c, x, y); - cairo_matrix_rotate(&c, amount); - cairo_matrix_translate(&c, -x, -y); - c2m(&c, m); -} - -void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount) -{ - fallbackSkew(m, x, y, xamount, yamount); -} - -void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src) -{ - cairo_matrix_t c; - cairo_matrix_t d; - - m2c(dest, &c); - m2c(src, &d); - cairo_matrix_multiply(&c, &c, &d); - c2m(&c, dest); -} - -int uiDrawMatrixInvertible(uiDrawMatrix *m) -{ - cairo_matrix_t c; - - m2c(m, &c); - return cairo_matrix_invert(&c) == CAIRO_STATUS_SUCCESS; -} - -int uiDrawMatrixInvert(uiDrawMatrix *m) -{ - cairo_matrix_t c; - - m2c(m, &c); - if (cairo_matrix_invert(&c) != CAIRO_STATUS_SUCCESS) - return 0; - c2m(&c, m); - return 1; -} - -void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y) -{ - cairo_matrix_t c; - - m2c(m, &c); - cairo_matrix_transform_point(&c, x, y); -} - -void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y) -{ - cairo_matrix_t c; - - m2c(m, &c); - cairo_matrix_transform_distance(&c, x, y); -} diff --git a/deps/libui/unix/drawpath.c b/deps/libui/unix/drawpath.c deleted file mode 100644 index a0165fb882..0000000000 --- a/deps/libui/unix/drawpath.c +++ /dev/null @@ -1,199 +0,0 @@ -// 6 september 2015 -#include "uipriv_unix.h" -#include "draw.h" - -struct uiDrawPath { - GArray *pieces; - uiDrawFillMode fillMode; - gboolean ended; -}; - -struct piece { - int type; - double d[8]; - int b; -}; - -enum { - newFigure, - newFigureArc, - lineTo, - arcTo, - bezierTo, - closeFigure, - addRect, -}; - -uiDrawPath *uiDrawNewPath(uiDrawFillMode mode) -{ - uiDrawPath *p; - - p = uiNew(uiDrawPath); - p->pieces = g_array_new(FALSE, TRUE, sizeof (struct piece)); - p->fillMode = mode; - return p; -} - -void uiDrawFreePath(uiDrawPath *p) -{ - g_array_free(p->pieces, TRUE); - uiFree(p); -} - -static void add(uiDrawPath *p, struct piece *piece) -{ - if (p->ended) - userbug("You cannot modify a uiDrawPath that has been ended. (path: %p)", p); - g_array_append_vals(p->pieces, piece, 1); -} - -void uiDrawPathNewFigure(uiDrawPath *p, double x, double y) -{ - struct piece piece; - - piece.type = newFigure; - piece.d[0] = x; - piece.d[1] = y; - add(p, &piece); -} - -void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative) -{ - struct piece piece; - - if (sweep > 2 * uiPi) - sweep = 2 * uiPi; - piece.type = newFigureArc; - piece.d[0] = xCenter; - piece.d[1] = yCenter; - piece.d[2] = radius; - piece.d[3] = startAngle; - piece.d[4] = sweep; - piece.b = negative; - add(p, &piece); -} - -void uiDrawPathLineTo(uiDrawPath *p, double x, double y) -{ - struct piece piece; - - piece.type = lineTo; - piece.d[0] = x; - piece.d[1] = y; - add(p, &piece); -} - -void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative) -{ - struct piece piece; - - if (sweep > 2 * uiPi) - sweep = 2 * uiPi; - piece.type = arcTo; - piece.d[0] = xCenter; - piece.d[1] = yCenter; - piece.d[2] = radius; - piece.d[3] = startAngle; - piece.d[4] = sweep; - piece.b = negative; - add(p, &piece); -} - -void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY) -{ - struct piece piece; - - piece.type = bezierTo; - piece.d[0] = c1x; - piece.d[1] = c1y; - piece.d[2] = c2x; - piece.d[3] = c2y; - piece.d[4] = endX; - piece.d[5] = endY; - add(p, &piece); -} - -void uiDrawPathCloseFigure(uiDrawPath *p) -{ - struct piece piece; - - piece.type = closeFigure; - add(p, &piece); -} - -void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height) -{ - struct piece piece; - - piece.type = addRect; - piece.d[0] = x; - piece.d[1] = y; - piece.d[2] = width; - piece.d[3] = height; - add(p, &piece); -} - -void uiDrawPathEnd(uiDrawPath *p) -{ - p->ended = TRUE; -} - -void runPath(uiDrawPath *p, cairo_t *cr) -{ - guint i; - struct piece *piece; - void (*arc)(cairo_t *, double, double, double, double, double); - - if (!p->ended) - userbug("You cannot draw with a uiDrawPath that has not been ended. (path: %p)", p); - cairo_new_path(cr); - for (i = 0; i < p->pieces->len; i++) { - piece = &g_array_index(p->pieces, struct piece, i); - switch (piece->type) { - case newFigure: - cairo_move_to(cr, piece->d[0], piece->d[1]); - break; - case newFigureArc: - cairo_new_sub_path(cr); - // fall through - case arcTo: - arc = cairo_arc; - if (piece->b) - arc = cairo_arc_negative; - (*arc)(cr, - piece->d[0], - piece->d[1], - piece->d[2], - piece->d[3], - piece->d[3] + piece->d[4]); - break; - case lineTo: - cairo_line_to(cr, piece->d[0], piece->d[1]); - break; - case bezierTo: - cairo_curve_to(cr, - piece->d[0], - piece->d[1], - piece->d[2], - piece->d[3], - piece->d[4], - piece->d[5]); - break; - case closeFigure: - cairo_close_path(cr); - break; - case addRect: - cairo_rectangle(cr, - piece->d[0], - piece->d[1], - piece->d[2], - piece->d[3]); - break; - } - } -} - -uiDrawFillMode pathFillMode(uiDrawPath *path) -{ - return path->fillMode; -} diff --git a/deps/libui/unix/drawtext.c b/deps/libui/unix/drawtext.c deleted file mode 100644 index 7078e1ac6a..0000000000 --- a/deps/libui/unix/drawtext.c +++ /dev/null @@ -1,293 +0,0 @@ -// 6 september 2015 -#include "uipriv_unix.h" -#include "draw.h" - -struct uiDrawFontFamilies { - PangoFontFamily **f; - int n; -}; - -uiDrawFontFamilies *uiDrawListFontFamilies(void) -{ - uiDrawFontFamilies *ff; - PangoFontMap *map; - - ff = uiNew(uiDrawFontFamilies); - map = pango_cairo_font_map_get_default(); - pango_font_map_list_families(map, &(ff->f), &(ff->n)); - // do not free map; it's a shared resource - return ff; -} - -int uiDrawFontFamiliesNumFamilies(uiDrawFontFamilies *ff) -{ - return ff->n; -} - -char *uiDrawFontFamiliesFamily(uiDrawFontFamilies *ff, int n) -{ - PangoFontFamily *f; - - f = ff->f[n]; - return uiUnixStrdupText(pango_font_family_get_name(f)); -} - -void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff) -{ - g_free(ff->f); - uiFree(ff); -} - -struct uiDrawTextFont { - PangoFont *f; -}; - -uiDrawTextFont *mkTextFont(PangoFont *f, gboolean ref) -{ - uiDrawTextFont *font; - - font = uiNew(uiDrawTextFont); - font->f = f; - if (ref) - g_object_ref(font->f); - return font; -} - -static const PangoWeight pangoWeights[] = { - [uiDrawTextWeightThin] = PANGO_WEIGHT_THIN, - [uiDrawTextWeightUltraLight] = PANGO_WEIGHT_ULTRALIGHT, - [uiDrawTextWeightLight] = PANGO_WEIGHT_LIGHT, - [uiDrawTextWeightBook] = PANGO_WEIGHT_BOOK, - [uiDrawTextWeightNormal] = PANGO_WEIGHT_NORMAL, - [uiDrawTextWeightMedium] = PANGO_WEIGHT_MEDIUM, - [uiDrawTextWeightSemiBold] = PANGO_WEIGHT_SEMIBOLD, - [uiDrawTextWeightBold] = PANGO_WEIGHT_BOLD, - [uiDrawTextWeightUltraBold] = PANGO_WEIGHT_ULTRABOLD, - [uiDrawTextWeightHeavy] = PANGO_WEIGHT_HEAVY, - [uiDrawTextWeightUltraHeavy] = PANGO_WEIGHT_ULTRAHEAVY, -}; - -static const PangoStyle pangoItalics[] = { - [uiDrawTextItalicNormal] = PANGO_STYLE_NORMAL, - [uiDrawTextItalicOblique] = PANGO_STYLE_OBLIQUE, - [uiDrawTextItalicItalic] = PANGO_STYLE_ITALIC, -}; - -static const PangoStretch pangoStretches[] = { - [uiDrawTextStretchUltraCondensed] = PANGO_STRETCH_ULTRA_CONDENSED, - [uiDrawTextStretchExtraCondensed] = PANGO_STRETCH_EXTRA_CONDENSED, - [uiDrawTextStretchCondensed] = PANGO_STRETCH_CONDENSED, - [uiDrawTextStretchSemiCondensed] = PANGO_STRETCH_SEMI_CONDENSED, - [uiDrawTextStretchNormal] = PANGO_STRETCH_NORMAL, - [uiDrawTextStretchSemiExpanded] = PANGO_STRETCH_SEMI_EXPANDED, - [uiDrawTextStretchExpanded] = PANGO_STRETCH_EXPANDED, - [uiDrawTextStretchExtraExpanded] = PANGO_STRETCH_EXTRA_EXPANDED, - [uiDrawTextStretchUltraExpanded] = PANGO_STRETCH_ULTRA_EXPANDED, -}; - -// we need a context for a few things -// the documentation suggests creating cairo_t-specific, GdkScreen-specific, or even GtkWidget-specific contexts, but we can't really do that because we want our uiDrawTextFonts and uiDrawTextLayouts to be context-independent -// we could use pango_font_map_create_context(pango_cairo_font_map_get_default()) but that will ignore GDK-specific settings -// so let's use gdk_pango_context_get() instead; even though it's for the default screen only, it's good enough for us -#define mkGenericPangoCairoContext() (gdk_pango_context_get()) - -PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc) -{ - PangoFont *f; - PangoContext *context; - - // in this case, the context is necessary for the metrics to be correct - context = mkGenericPangoCairoContext(); - f = pango_font_map_load_font(pango_cairo_font_map_get_default(), context, pdesc); - if (f == NULL) { - // LONGTERM - g_error("[libui] no match in pangoDescToPangoFont(); report to andlabs"); - } - g_object_unref(context); - return f; -} - -uiDrawTextFont *uiDrawLoadClosestFont(const uiDrawTextFontDescriptor *desc) -{ - PangoFont *f; - PangoFontDescription *pdesc; - - pdesc = pango_font_description_new(); - pango_font_description_set_family(pdesc, - desc->Family); - pango_font_description_set_size(pdesc, - (gint) (desc->Size * PANGO_SCALE)); - pango_font_description_set_weight(pdesc, - pangoWeights[desc->Weight]); - pango_font_description_set_style(pdesc, - pangoItalics[desc->Italic]); - pango_font_description_set_stretch(pdesc, - pangoStretches[desc->Stretch]); - f = pangoDescToPangoFont(pdesc); - pango_font_description_free(pdesc); - return mkTextFont(f, FALSE); // we hold the initial reference; no need to ref -} - -void uiDrawFreeTextFont(uiDrawTextFont *font) -{ - g_object_unref(font->f); - uiFree(font); -} - -uintptr_t uiDrawTextFontHandle(uiDrawTextFont *font) -{ - return (uintptr_t) (font->f); -} - -void uiDrawTextFontDescribe(uiDrawTextFont *font, uiDrawTextFontDescriptor *desc) -{ - PangoFontDescription *pdesc; - - // this creates a copy; we free it later - pdesc = pango_font_describe(font->f); - - // TODO - - pango_font_description_free(pdesc); -} - -// See https://developer.gnome.org/pango/1.30/pango-Cairo-Rendering.html#pango-Cairo-Rendering.description -// Note that we convert to double before dividing to make sure the floating-point stuff is right -#define pangoToCairo(pango) (((double) (pango)) / PANGO_SCALE) -#define cairoToPango(cairo) ((gint) ((cairo) * PANGO_SCALE)) - -void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metrics) -{ - PangoFontMetrics *pm; - - pm = pango_font_get_metrics(font->f, NULL); - metrics->Ascent = pangoToCairo(pango_font_metrics_get_ascent(pm)); - metrics->Descent = pangoToCairo(pango_font_metrics_get_descent(pm)); - // Pango doesn't seem to expose this :( Use 0 and hope for the best. - metrics->Leading = 0; - metrics->UnderlinePos = pangoToCairo(pango_font_metrics_get_underline_position(pm)); - metrics->UnderlineThickness = pangoToCairo(pango_font_metrics_get_underline_thickness(pm)); - pango_font_metrics_unref(pm); -} - -// note: PangoCairoLayouts are tied to a given cairo_t, so we can't store one in this device-independent structure -struct uiDrawTextLayout { - char *s; - ptrdiff_t *graphemes; - PangoFont *defaultFont; - double width; - PangoAttrList *attrs; -}; - -uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultFont, double width) -{ - uiDrawTextLayout *layout; - PangoContext *context; - - layout = uiNew(uiDrawTextLayout); - layout->s = g_strdup(text); - context = mkGenericPangoCairoContext(); - layout->graphemes = graphemes(layout->s, context); - g_object_unref(context); - layout->defaultFont = defaultFont->f; - g_object_ref(layout->defaultFont); // retain a copy - uiDrawTextLayoutSetWidth(layout, width); - layout->attrs = pango_attr_list_new(); - return layout; -} - -void uiDrawFreeTextLayout(uiDrawTextLayout *layout) -{ - pango_attr_list_unref(layout->attrs); - g_object_unref(layout->defaultFont); - uiFree(layout->graphemes); - g_free(layout->s); - uiFree(layout); -} - -void uiDrawTextLayoutSetWidth(uiDrawTextLayout *layout, double width) -{ - layout->width = width; -} - -static void prepareLayout(uiDrawTextLayout *layout, PangoLayout *pl) -{ - PangoFontDescription *desc; - int width; - - pango_layout_set_text(pl, layout->s, -1); - - // again, this makes a copy - desc = pango_font_describe(layout->defaultFont); - // this is safe; the description is copied - pango_layout_set_font_description(pl, desc); - pango_font_description_free(desc); - - width = cairoToPango(layout->width); - if (layout->width < 0) - width = -1; - pango_layout_set_width(pl, width); - - pango_layout_set_attributes(pl, layout->attrs); -} - -void uiDrawTextLayoutExtents(uiDrawTextLayout *layout, double *width, double *height) -{ - PangoContext *context; - PangoLayout *pl; - PangoRectangle logical; - - // in this case, the context is necessary to create the layout - // the layout takes a ref on the context so we can unref it afterward - context = mkGenericPangoCairoContext(); - pl = pango_layout_new(context); - g_object_unref(context); - prepareLayout(layout, pl); - - pango_layout_get_extents(pl, NULL, &logical); - - g_object_unref(pl); - - *width = pangoToCairo(logical.width); - *height = pangoToCairo(logical.height); -} - -void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout) -{ - PangoLayout *pl; - - pl = pango_cairo_create_layout(c->cr); - prepareLayout(layout, pl); - - cairo_move_to(c->cr, x, y); - pango_cairo_show_layout(c->cr, pl); - - g_object_unref(pl); -} - -static void addAttr(uiDrawTextLayout *layout, PangoAttribute *attr, int startChar, int endChar) -{ - attr->start_index = layout->graphemes[startChar]; - attr->end_index = layout->graphemes[endChar]; - pango_attr_list_insert(layout->attrs, attr); - // pango_attr_list_insert() takes attr; we don't free it -} - -void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endChar, double r, double g, double b, double a) -{ - PangoAttribute *attr; - guint16 rr, gg, bb, aa; - - rr = (guint16) (r * 65535); - gg = (guint16) (g * 65535); - bb = (guint16) (b * 65535); - aa = (guint16) (a * 65535); - - attr = pango_attr_foreground_new(rr, gg, bb); - addAttr(layout, attr, startChar, endChar); - - // TODO what if aa == 0? - attr = FUTURE_pango_attr_foreground_alpha_new(aa); - if (attr != NULL) - addAttr(layout, attr, startChar, endChar); -} diff --git a/deps/libui/unix/editablecombo.c b/deps/libui/unix/editablecombo.c deleted file mode 100644 index 7ee3829eea..0000000000 --- a/deps/libui/unix/editablecombo.c +++ /dev/null @@ -1,79 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiEditableCombobox { - uiUnixControl c; - GtkWidget *widget; - GtkBin *bin; - GtkComboBox *combobox; - GtkComboBoxText *comboboxText; - void (*onChanged)(uiEditableCombobox *, void *); - void *onChangedData; - gulong onChangedSignal; -}; - -uiUnixControlAllDefaults(uiEditableCombobox) - -static void onChanged(GtkComboBox *cbox, gpointer data) -{ - uiEditableCombobox *c = uiEditableCombobox(data); - - (*(c->onChanged))(c, c->onChangedData); -} - -static void defaultOnChanged(uiEditableCombobox *c, void *data) -{ - // do nothing -} - -void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text) -{ - gtk_combo_box_text_append(c->comboboxText, NULL, text); -} - -char *uiEditableComboboxText(uiEditableCombobox *c) -{ - char *s; - char *out; - - s = gtk_combo_box_text_get_active_text(c->comboboxText); - // s will always be non-NULL in the case of a combobox with an entry (according to the source code) - out = uiUnixStrdupText(s); - g_free(s); - return out; -} - -void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text) -{ - GtkEntry *e; - - // we need to inhibit sending of ::changed because this WILL send a ::changed otherwise - g_signal_handler_block(c->combobox, c->onChangedSignal); - // since there isn't a gtk_combo_box_text_set_active_text()... - e = GTK_ENTRY(gtk_bin_get_child(c->bin)); - gtk_entry_set_text(e, text); - g_signal_handler_unblock(c->combobox, c->onChangedSignal); -} - -void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data) -{ - c->onChanged = f; - c->onChangedData = data; -} - -uiEditableCombobox *uiNewEditableCombobox(void) -{ - uiEditableCombobox *c; - - uiUnixNewControl(uiEditableCombobox, c); - - c->widget = gtk_combo_box_text_new_with_entry(); - c->bin = GTK_BIN(c->widget); - c->combobox = GTK_COMBO_BOX(c->widget); - c->comboboxText = GTK_COMBO_BOX_TEXT(c->widget); - - c->onChangedSignal = g_signal_connect(c->widget, "changed", G_CALLBACK(onChanged), c); - uiEditableComboboxOnChanged(c, defaultOnChanged, NULL); - - return c; -} diff --git a/deps/libui/unix/entry.c b/deps/libui/unix/entry.c deleted file mode 100644 index 4a9a1d0410..0000000000 --- a/deps/libui/unix/entry.c +++ /dev/null @@ -1,97 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiEntry { - uiUnixControl c; - GtkWidget *widget; - GtkEntry *entry; - GtkEditable *editable; - void (*onChanged)(uiEntry *, void *); - void *onChangedData; - gulong onChangedSignal; -}; - -uiUnixControlAllDefaults(uiEntry) - -static void onChanged(GtkEditable *editable, gpointer data) -{ - uiEntry *e = uiEntry(data); - - (*(e->onChanged))(e, e->onChangedData); -} - -static void defaultOnChanged(uiEntry *e, void *data) -{ - // do nothing -} - -char *uiEntryText(uiEntry *e) -{ - return uiUnixStrdupText(gtk_entry_get_text(e->entry)); -} - -void uiEntrySetText(uiEntry *e, const char *text) -{ - // we need to inhibit sending of ::changed because this WILL send a ::changed otherwise - g_signal_handler_block(e->editable, e->onChangedSignal); - gtk_entry_set_text(e->entry, text); - g_signal_handler_unblock(e->editable, e->onChangedSignal); - // don't queue the control for resize; entry sizes are independent of their contents -} - -void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *, void *), void *data) -{ - e->onChanged = f; - e->onChangedData = data; -} - -int uiEntryReadOnly(uiEntry *e) -{ - return gtk_editable_get_editable(e->editable) == FALSE; -} - -void uiEntrySetReadOnly(uiEntry *e, int readonly) -{ - gboolean editable; - - editable = TRUE; - if (readonly) - editable = FALSE; - gtk_editable_set_editable(e->editable, editable); -} - -static uiEntry *finishNewEntry(GtkWidget *w, const gchar *signal) -{ - uiEntry *e; - - uiUnixNewControl(uiEntry, e); - - e->widget = w; - e->entry = GTK_ENTRY(e->widget); - e->editable = GTK_EDITABLE(e->widget); - - e->onChangedSignal = g_signal_connect(e->widget, signal, G_CALLBACK(onChanged), e); - uiEntryOnChanged(e, defaultOnChanged, NULL); - - return e; -} - -uiEntry *uiNewEntry(void) -{ - return finishNewEntry(gtk_entry_new(), "changed"); -} - -uiEntry *uiNewPasswordEntry(void) -{ - GtkWidget *e; - - e = gtk_entry_new(); - gtk_entry_set_visibility(GTK_ENTRY(e), FALSE); - return finishNewEntry(e, "changed"); -} - -// TODO make it use a separate function to be type-safe -uiEntry *uiNewSearchEntry(void) -{ - return finishNewEntry(gtk_search_entry_new(), "search-changed"); -} diff --git a/deps/libui/unix/fontbutton.c b/deps/libui/unix/fontbutton.c deleted file mode 100644 index f8047e0803..0000000000 --- a/deps/libui/unix/fontbutton.c +++ /dev/null @@ -1,70 +0,0 @@ -// 14 april 2016 -#include "uipriv_unix.h" - -struct uiFontButton { - uiUnixControl c; - GtkWidget *widget; - GtkButton *button; - GtkFontButton *fb; - GtkFontChooser *fc; - void (*onChanged)(uiFontButton *, void *); - void *onChangedData; -}; - -uiUnixControlAllDefaults(uiFontButton) - -// TODO NOTE no need to inhibit the signal; font-set is documented as only being sent when the user changes the font -static void onFontSet(GtkFontButton *button, gpointer data) -{ - uiFontButton *b = uiFontButton(data); - - (*(b->onChanged))(b, b->onChangedData); -} - -static void defaultOnChanged(uiFontButton *b, void *data) -{ - // do nothing -} - -uiDrawTextFont *uiFontButtonFont(uiFontButton *b) -{ - PangoFont *f; - PangoFontDescription *desc; - - desc = gtk_font_chooser_get_font_desc(b->fc); - f = pangoDescToPangoFont(desc); - // desc is transfer-full and thus is a copy - pango_font_description_free(desc); - return mkTextFont(f, FALSE); // we hold the initial reference; no need to ref -} - -void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data) -{ - b->onChanged = f; - b->onChangedData = data; -} - -uiFontButton *uiNewFontButton(void) -{ - uiFontButton *b; - - uiUnixNewControl(uiFontButton, b); - - b->widget = gtk_font_button_new(); - b->button = GTK_BUTTON(b->widget); - b->fb = GTK_FONT_BUTTON(b->widget); - b->fc = GTK_FONT_CHOOSER(b->widget); - - // match behavior on other platforms - gtk_font_button_set_show_style(b->fb, TRUE); - gtk_font_button_set_show_size(b->fb, TRUE); - gtk_font_button_set_use_font(b->fb, FALSE); - gtk_font_button_set_use_size(b->fb, FALSE); - // other customizations - gtk_font_chooser_set_show_preview_entry(b->fc, TRUE); - - g_signal_connect(b->widget, "font-set", G_CALLBACK(onFontSet), b); - uiFontButtonOnChanged(b, defaultOnChanged, NULL); - - return b; -} diff --git a/deps/libui/unix/form.c b/deps/libui/unix/form.c deleted file mode 100644 index 54422b3d40..0000000000 --- a/deps/libui/unix/form.c +++ /dev/null @@ -1,159 +0,0 @@ -// 8 june 2016 -#include "uipriv_unix.h" - -struct formChild { - uiControl *c; - int stretchy; - GtkWidget *label; - gboolean oldhexpand; - GtkAlign oldhalign; - gboolean oldvexpand; - GtkAlign oldvalign; - GBinding *labelBinding; -}; - -struct uiForm { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkGrid *grid; - GArray *children; - int padded; - GtkSizeGroup *stretchygroup; // ensures all stretchy controls have the same size -}; - -uiUnixControlAllDefaultsExceptDestroy(uiForm) - -#define ctrl(f, i) &g_array_index(f->children, struct formChild, i) - -static void uiFormDestroy(uiControl *c) -{ - uiForm *f = uiForm(c); - struct formChild *fc; - guint i; - - // kill the size group - g_object_unref(f->stretchygroup); - // free all controls - for (i = 0; i < f->children->len; i++) { - fc = ctrl(f, i); - uiControlSetParent(fc->c, NULL); - uiUnixControlSetContainer(uiUnixControl(fc->c), f->container, TRUE); - uiControlDestroy(fc->c); - gtk_widget_destroy(fc->label); - } - g_array_free(f->children, TRUE); - // and then ourselves - g_object_unref(f->widget); - uiFreeControl(uiControl(f)); -} - -void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy) -{ - struct formChild fc; - GtkWidget *widget; - guint row; - - fc.c = c; - widget = GTK_WIDGET(uiControlHandle(fc.c)); - fc.stretchy = stretchy; - fc.oldhexpand = gtk_widget_get_hexpand(widget); - fc.oldhalign = gtk_widget_get_halign(widget); - fc.oldvexpand = gtk_widget_get_vexpand(widget); - fc.oldvalign = gtk_widget_get_valign(widget); - - if (stretchy) { - gtk_widget_set_vexpand(widget, TRUE); - gtk_widget_set_valign(widget, GTK_ALIGN_FILL); - gtk_size_group_add_widget(f->stretchygroup, widget); - } else - gtk_widget_set_vexpand(widget, FALSE); - // and make them fill horizontally - gtk_widget_set_hexpand(widget, TRUE); - gtk_widget_set_halign(widget, GTK_ALIGN_FILL); - - fc.label = gtk_label_new(label); - gtk_widget_set_hexpand(fc.label, FALSE); - gtk_widget_set_halign(fc.label, GTK_ALIGN_END); - gtk_widget_set_vexpand(fc.label, FALSE); - if (GTK_IS_SCROLLED_WINDOW(widget)) - gtk_widget_set_valign(fc.label, GTK_ALIGN_START); - else - gtk_widget_set_valign(fc.label, GTK_ALIGN_CENTER); - gtk_style_context_add_class(gtk_widget_get_style_context(fc.label), "dim-label"); - row = f->children->len; - gtk_grid_attach(f->grid, fc.label, - 0, row, - 1, 1); - // and make them share visibility so if the control is hidden, so is its label - fc.labelBinding = g_object_bind_property(GTK_WIDGET(uiControlHandle(fc.c)), "visible", - fc.label, "visible", - G_BINDING_SYNC_CREATE); - - uiControlSetParent(fc.c, uiControl(f)); - uiUnixControlSetContainer(uiUnixControl(fc.c), f->container, FALSE); - g_array_append_val(f->children, fc); - - // move the widget to the correct place - gtk_container_child_set(f->container, widget, - "left-attach", 1, - "top-attach", row, - NULL); -} - -void uiFormDelete(uiForm *f, int index) -{ - struct formChild *fc; - GtkWidget *widget; - - fc = ctrl(f, index); - widget = GTK_WIDGET(uiControlHandle(fc->c)); - - gtk_widget_destroy(fc->label); - - uiControlSetParent(fc->c, NULL); - uiUnixControlSetContainer(uiUnixControl(fc->c), f->container, TRUE); - - if (fc->stretchy) - gtk_size_group_remove_widget(f->stretchygroup, widget); - gtk_widget_set_hexpand(widget, fc->oldhexpand); - gtk_widget_set_halign(widget, fc->oldhalign); - gtk_widget_set_vexpand(widget, fc->oldvexpand); - gtk_widget_set_valign(widget, fc->oldvalign); - - g_array_remove_index(f->children, index); -} - -int uiFormPadded(uiForm *f) -{ - return f->padded; -} - -void uiFormSetPadded(uiForm *f, int padded) -{ - f->padded = padded; - if (f->padded) { - gtk_grid_set_row_spacing(f->grid, gtkYPadding); - gtk_grid_set_column_spacing(f->grid, gtkXPadding); - } else { - gtk_grid_set_row_spacing(f->grid, 0); - gtk_grid_set_column_spacing(f->grid, 0); - } -} - -uiForm *uiNewForm(void) -{ - uiForm *f; - - uiUnixNewControl(uiForm, f); - - f->widget = gtk_grid_new(); - f->container = GTK_CONTAINER(f->widget); - f->grid = GTK_GRID(f->widget); - - f->stretchygroup = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL); - - f->children = g_array_new(FALSE, TRUE, sizeof (struct formChild)); - - return f; -} diff --git a/deps/libui/unix/future.c b/deps/libui/unix/future.c deleted file mode 100644 index 1f9f532b11..0000000000 --- a/deps/libui/unix/future.c +++ /dev/null @@ -1,42 +0,0 @@ -// 29 june 2016 -#include "uipriv_unix.h" - -// functions FROM THE FUTURE! -// in some cases, because being held back by LTS releases sucks :/ -// in others, because parts of GTK+ being unstable until recently also sucks :/ - -// added in pango 1.38; we need 1.36 -static PangoAttribute *(*newFGAlphaAttr)(guint16 alpha) = NULL; - -// added in GTK+ 3.20; we need 3.10 -static void (*gwpIterSetObjectName)(GtkWidgetPath *path, gint pos, const char *name) = NULL; - -// note that we treat any error as "the symbols aren't there" (and don't care if dlclose() failed) -void loadFutures(void) -{ - void *handle; - - // dlsym() walks the dependency chain, so opening the current process should be sufficient - handle = dlopen(NULL, RTLD_LAZY); - if (handle == NULL) - return; -#define GET(var, fn) *((void **) (&var)) = dlsym(handle, #fn) - GET(newFGAlphaAttr, pango_attr_foreground_alpha_new); - GET(gwpIterSetObjectName, gtk_widget_path_iter_set_object_name); - dlclose(handle); -} - -PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha) -{ - if (newFGAlphaAttr == NULL) - return NULL; - return (*newFGAlphaAttr)(alpha); -} - -gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name) -{ - if (gwpIterSetObjectName == NULL) - return FALSE; - (*gwpIterSetObjectName)(path, pos, name); - return TRUE; -} diff --git a/deps/libui/unix/graphemes.c b/deps/libui/unix/graphemes.c deleted file mode 100644 index a2c47b7251..0000000000 --- a/deps/libui/unix/graphemes.c +++ /dev/null @@ -1,31 +0,0 @@ -// 25 may 2016 -#include "uipriv_unix.h" - -ptrdiff_t *graphemes(const char *text, PangoContext *context) -{ - size_t len, lenchars; - PangoLogAttr *logattrs; - ptrdiff_t *out; - ptrdiff_t *op; - size_t i; - - len = strlen(text); - lenchars = g_utf8_strlen(text, -1); - logattrs = (PangoLogAttr *) uiAlloc((lenchars + 1) * sizeof (PangoLogAttr), "PangoLogAttr[]"); - pango_get_log_attrs(text, len, - -1, NULL, - logattrs, lenchars + 1); - - // should be more than enough - out = (ptrdiff_t *) uiAlloc((lenchars + 2) * sizeof (ptrdiff_t), "ptrdiff_t[]"); - op = out; - for (i = 0; i < lenchars; i++) - if (logattrs[i].is_cursor_position != 0) - // TODO optimize this - *op++ = g_utf8_offset_to_pointer(text, i) - text; - // and do the last one - *op++ = len; - - uiFree(logattrs); - return out; -} diff --git a/deps/libui/unix/grid.c b/deps/libui/unix/grid.c deleted file mode 100644 index 6d9813b35d..0000000000 --- a/deps/libui/unix/grid.c +++ /dev/null @@ -1,141 +0,0 @@ -// 9 june 2016 -#include "uipriv_unix.h" - -struct gridChild { - uiControl *c; - GtkWidget *label; - gboolean oldhexpand; - GtkAlign oldhalign; - gboolean oldvexpand; - GtkAlign oldvalign; -}; - -struct uiGrid { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkGrid *grid; - GArray *children; - int padded; -}; - -uiUnixControlAllDefaultsExceptDestroy(uiGrid) - -#define ctrl(g, i) &g_array_index(g->children, struct gridChild, i) - -static void uiGridDestroy(uiControl *c) -{ - uiGrid *g = uiGrid(c); - struct gridChild *gc; - guint i; - - // free all controls - for (i = 0; i < g->children->len; i++) { - gc = ctrl(g, i); - uiControlSetParent(gc->c, NULL); - uiUnixControlSetContainer(uiUnixControl(gc->c), g->container, TRUE); - uiControlDestroy(gc->c); - } - g_array_free(g->children, TRUE); - // and then ourselves - g_object_unref(g->widget); - uiFreeControl(uiControl(g)); -} - -#define TODO_MASSIVE_HACK(c) \ - if (!uiUnixControl(c)->addedBefore) { \ - g_object_ref_sink(GTK_WIDGET(uiControlHandle(uiControl(c)))); \ - gtk_widget_show(GTK_WIDGET(uiControlHandle(uiControl(c)))); \ - uiUnixControl(c)->addedBefore = TRUE; \ - } - -static const GtkAlign gtkAligns[] = { - [uiAlignFill] = GTK_ALIGN_FILL, - [uiAlignStart] = GTK_ALIGN_START, - [uiAlignCenter] = GTK_ALIGN_CENTER, - [uiAlignEnd] = GTK_ALIGN_END, -}; - -static const GtkPositionType gtkPositions[] = { - [uiAtLeading] = GTK_POS_LEFT, - [uiAtTop] = GTK_POS_TOP, - [uiAtTrailing] = GTK_POS_RIGHT, - [uiAtBottom] = GTK_POS_BOTTOM, -}; - -static GtkWidget *prepare(struct gridChild *gc, uiControl *c, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - GtkWidget *widget; - - gc->c = c; - widget = GTK_WIDGET(uiControlHandle(gc->c)); - gc->oldhexpand = gtk_widget_get_hexpand(widget); - gc->oldhalign = gtk_widget_get_halign(widget); - gc->oldvexpand = gtk_widget_get_vexpand(widget); - gc->oldvalign = gtk_widget_get_valign(widget); - gtk_widget_set_hexpand(widget, hexpand != 0); - gtk_widget_set_halign(widget, gtkAligns[halign]); - gtk_widget_set_vexpand(widget, vexpand != 0); - gtk_widget_set_valign(widget, gtkAligns[valign]); - return widget; -} - -void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - struct gridChild gc; - GtkWidget *widget; - - widget = prepare(&gc, c, hexpand, halign, vexpand, valign); - uiControlSetParent(gc.c, uiControl(g)); - TODO_MASSIVE_HACK(uiUnixControl(gc.c)); - gtk_grid_attach(g->grid, widget, - left, top, - xspan, yspan); - g_array_append_val(g->children, gc); -} - -void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - struct gridChild gc; - GtkWidget *widget; - - widget = prepare(&gc, c, hexpand, halign, vexpand, valign); - uiControlSetParent(gc.c, uiControl(g)); - TODO_MASSIVE_HACK(uiUnixControl(gc.c)); - gtk_grid_attach_next_to(g->grid, widget, - GTK_WIDGET(uiControlHandle(existing)), gtkPositions[at], - xspan, yspan); - g_array_append_val(g->children, gc); -} - -int uiGridPadded(uiGrid *g) -{ - return g->padded; -} - -void uiGridSetPadded(uiGrid *g, int padded) -{ - g->padded = padded; - if (g->padded) { - gtk_grid_set_row_spacing(g->grid, gtkYPadding); - gtk_grid_set_column_spacing(g->grid, gtkXPadding); - } else { - gtk_grid_set_row_spacing(g->grid, 0); - gtk_grid_set_column_spacing(g->grid, 0); - } -} - -uiGrid *uiNewGrid(void) -{ - uiGrid *g; - - uiUnixNewControl(uiGrid, g); - - g->widget = gtk_grid_new(); - g->container = GTK_CONTAINER(g->widget); - g->grid = GTK_GRID(g->widget); - - g->children = g_array_new(FALSE, TRUE, sizeof (struct gridChild)); - - return g; -} diff --git a/deps/libui/unix/group.c b/deps/libui/unix/group.c deleted file mode 100644 index 6238a1b650..0000000000 --- a/deps/libui/unix/group.c +++ /dev/null @@ -1,89 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiGroup { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkBin *bin; - GtkFrame *frame; - - // unfortunately, even though a GtkFrame is a GtkBin, calling gtk_container_set_border_width() on it /includes/ the GtkFrame's label; we don't want tht - struct child *child; - - int margined; -}; - -uiUnixControlAllDefaultsExceptDestroy(uiGroup) - -static void uiGroupDestroy(uiControl *c) -{ - uiGroup *g = uiGroup(c); - - if (g->child != NULL) - childDestroy(g->child); - g_object_unref(g->widget); - uiFreeControl(uiControl(g)); -} - -char *uiGroupTitle(uiGroup *g) -{ - return uiUnixStrdupText(gtk_frame_get_label(g->frame)); -} - -void uiGroupSetTitle(uiGroup *g, const char *text) -{ - gtk_frame_set_label(g->frame, text); -} - -void uiGroupSetChild(uiGroup *g, uiControl *child) -{ - if (g->child != NULL) - childRemove(g->child); - g->child = newChildWithBox(child, uiControl(g), g->container, g->margined); -} - -int uiGroupMargined(uiGroup *g) -{ - return g->margined; -} - -void uiGroupSetMargined(uiGroup *g, int margined) -{ - g->margined = margined; - if (g->child != NULL) - childSetMargined(g->child, g->margined); -} - -uiGroup *uiNewGroup(const char *text) -{ - uiGroup *g; - gfloat yalign; - GtkLabel *label; - PangoAttribute *bold; - PangoAttrList *boldlist; - - uiUnixNewControl(uiGroup, g); - - g->widget = gtk_frame_new(text); - g->container = GTK_CONTAINER(g->widget); - g->bin = GTK_BIN(g->widget); - g->frame = GTK_FRAME(g->widget); - - // with GTK+, groupboxes by default have frames and slightly x-offset regular text - // they should have no frame and fully left-justified, bold text - // preserve default y-alignment - gtk_frame_get_label_align(g->frame, NULL, &yalign); - gtk_frame_set_label_align(g->frame, 0, yalign); - gtk_frame_set_shadow_type(g->frame, GTK_SHADOW_NONE); - label = GTK_LABEL(gtk_frame_get_label_widget(g->frame)); - // this is the boldness level used by GtkPrintUnixDialog - // (it technically uses "bold" but see pango's pango-enum-types.c for the name conversion; GType is weird) - bold = pango_attr_weight_new(PANGO_WEIGHT_BOLD); - boldlist = pango_attr_list_new(); - pango_attr_list_insert(boldlist, bold); - gtk_label_set_attributes(label, boldlist); - pango_attr_list_unref(boldlist); // thanks baedert in irc.gimp.net/#gtk+ - - return g; -} diff --git a/deps/libui/unix/image.c b/deps/libui/unix/image.c deleted file mode 100644 index a79e550f93..0000000000 --- a/deps/libui/unix/image.c +++ /dev/null @@ -1,120 +0,0 @@ -// 27 june 2016 -#include "uipriv_unix.h" - -struct uiImage { - double width; - double height; - GPtrArray *images; -}; - -static void freeImageRep(gpointer item) -{ - cairo_surface_t *cs = (cairo_surface_t *) item; - unsigned char *buf; - - buf = cairo_image_surface_get_data(cs); - cairo_surface_destroy(cs); - uiFree(buf); -} - -uiImage *uiNewImage(double width, double height) -{ - uiImage *i; - - i = uiNew(uiImage); - i->width = width; - i->height = height; - i->images = g_ptr_array_new_with_free_func(freeImageRep); - return i; -} - -void uiFreeImage(uiImage *i) -{ - g_ptr_array_free(i->images, TRUE); - uiFree(i); -} - -void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, int pixelStride) -{ - cairo_surface_t *cs; - unsigned char *buf, *p; - uint8_t *src = (uint8_t *) pixels; - int cstride; - int y; - - cstride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixelWidth); - buf = (unsigned char *) uiAlloc((cstride * pixelHeight * 4) * sizeof (unsigned char), "unsigned char[]"); - p = buf; - for (y = 0; y < pixelStride * pixelHeight; y += pixelStride) { - memmove(p, src + y, cstride); - p += cstride; - } - cs = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32, - pixelWidth, pixelHeight, - cstride); - if (cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) - /* TODO */; - cairo_surface_flush(cs); - g_ptr_array_add(i->images, cs); -} - -struct matcher { - cairo_surface_t *best; - int distX; - int distY; - int targetX; - int targetY; - gboolean foundLarger; -}; - -// TODO is this the right algorithm? -static void match(gpointer surface, gpointer data) -{ - cairo_surface_t *cs = (cairo_surface_t *) surface; - struct matcher *m = (struct matcher *) data; - int x, y; - int x2, y2; - - x = cairo_image_surface_get_width(cs); - y = cairo_image_surface_get_height(cs); - if (m->best == NULL) - goto writeMatch; - - if (x < m->targetX && y < m->targetY) - if (m->foundLarger) - // always prefer larger ones - return; - if (x >= m->targetX && y >= m->targetY && !m->foundLarger) - // we set foundLarger below - goto writeMatch; - - x2 = abs(m->targetX - x); - y2 = abs(m->targetY - y); - if (x2 < m->distX && y2 < m->distY) - goto writeMatch; - - // TODO weight one dimension? threshhold? - return; - -writeMatch: - // must set this here too; otherwise the first image will never have ths set - if (x >= m->targetX && y >= m->targetY && !m->foundLarger) - m->foundLarger = TRUE; - m->best = cs; - m->distX = abs(m->targetX - x); - m->distY = abs(m->targetY - y); -} - -cairo_surface_t *imageAppropriateSurface(uiImage *i, GtkWidget *w) -{ - struct matcher m; - - m.best = NULL; - m.distX = G_MAXINT; - m.distY = G_MAXINT; - m.targetX = i->width * gtk_widget_get_scale_factor(w); - m.targetY = i->height * gtk_widget_get_scale_factor(w); - m.foundLarger = FALSE; - g_ptr_array_foreach(i->images, match, &m); - return m.best; -} diff --git a/deps/libui/unix/label.c b/deps/libui/unix/label.c deleted file mode 100644 index b39fc7ccd0..0000000000 --- a/deps/libui/unix/label.c +++ /dev/null @@ -1,36 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiLabel { - uiUnixControl c; - GtkWidget *widget; - GtkMisc *misc; - GtkLabel *label; -}; - -uiUnixControlAllDefaults(uiLabel) - -char *uiLabelText(uiLabel *l) -{ - return uiUnixStrdupText(gtk_label_get_text(l->label)); -} - -void uiLabelSetText(uiLabel *l, const char *text) -{ - gtk_label_set_text(l->label, text); -} - -uiLabel *uiNewLabel(const char *text) -{ - uiLabel *l; - - uiUnixNewControl(uiLabel, l); - - l->widget = gtk_label_new(text); - l->misc = GTK_MISC(l->widget); - l->label = GTK_LABEL(l->widget); - - gtk_misc_set_alignment(l->misc, 0, 0); - - return l; -} diff --git a/deps/libui/unix/main.c b/deps/libui/unix/main.c deleted file mode 100644 index 2998bf3194..0000000000 --- a/deps/libui/unix/main.c +++ /dev/null @@ -1,108 +0,0 @@ -// 6 april 2015 -#include "uipriv_unix.h" - -uiInitOptions options; - -const char *uiInit(uiInitOptions *o) -{ - GError *err = NULL; - const char *msg; - - options = *o; - if (gtk_init_with_args(NULL, NULL, NULL, NULL, NULL, &err) == FALSE) { - msg = g_strdup(err->message); - g_error_free(err); - return msg; - } - initAlloc(); - loadFutures(); - return NULL; -} - -void uiUninit(void) -{ - uninitMenus(); - uninitAlloc(); -} - -void uiFreeInitError(const char *err) -{ - g_free((gpointer) err); -} - -static gboolean (*iteration)(gboolean) = NULL; - -void uiMain(void) -{ - iteration = gtk_main_iteration_do; - gtk_main(); -} - -static gboolean stepsQuit = FALSE; - -// the only difference is we ignore the return value from gtk_main_iteration_do(), since it will always be TRUE if gtk_main() was never called -// gtk_main_iteration_do() will still run the main loop regardless -static gboolean stepsIteration(gboolean block) -{ - gtk_main_iteration_do(block); - return stepsQuit; -} - -void uiMainSteps(void) -{ - iteration = stepsIteration; -} - -int uiMainStep(int wait) -{ - gboolean block; - - block = FALSE; - if (wait) - block = TRUE; - return (*iteration)(block) == FALSE; -} - -// gtk_main_quit() may run immediately, or it may wait for other pending events; "it depends" (thanks mclasen in irc.gimp.net/#gtk+) -// PostQuitMessage() on Windows always waits, so we must do so too -// we'll do it by using an idle callback -static gboolean quit(gpointer data) -{ - if (iteration == stepsIteration) - stepsQuit = TRUE; - // TODO run a gtk_main() here just to do the cleanup steps of syncing the clipboard and other stuff gtk_main() does before it returns - else - gtk_main_quit(); - return FALSE; -} - -void uiQuit(void) -{ - gdk_threads_add_idle(quit, NULL); -} - -struct queued { - void (*f)(void *); - void *data; -}; - -static gboolean doqueued(gpointer data) -{ - struct queued *q = (struct queued *) data; - - (*(q->f))(q->data); - g_free(q); - return FALSE; -} - -void uiQueueMain(void (*f)(void *data), void *data) -{ - struct queued *q; - - // we have to use g_new0()/g_free() because uiAlloc() is only safe to call on the main thread - // for some reason it didn't affect me, but it did affect krakjoe - q = g_new0(struct queued, 1); - q->f = f; - q->data = data; - gdk_threads_add_idle(doqueued, q); -} diff --git a/deps/libui/unix/menu.c b/deps/libui/unix/menu.c deleted file mode 100644 index 5ccb4a51a3..0000000000 --- a/deps/libui/unix/menu.c +++ /dev/null @@ -1,366 +0,0 @@ -// 23 april 2015 -#include "uipriv_unix.h" - -static GArray *menus = NULL; -static gboolean menusFinalized = FALSE; -static gboolean hasQuit = FALSE; -static gboolean hasPreferences = FALSE; -static gboolean hasAbout = FALSE; - -struct uiMenu { - char *name; - GArray *items; // []*uiMenuItem -}; - -struct uiMenuItem { - char *name; - int type; - void (*onClicked)(uiMenuItem *, uiWindow *, void *); - void *onClickedData; - GType gtype; // template for new instances; kept in sync with everything else - gboolean disabled; - gboolean checked; - GHashTable *windows; // map[GtkMenuItem]*menuItemWindow -}; - -struct menuItemWindow { - uiWindow *w; - gulong signal; -}; - -enum { - typeRegular, - typeCheckbox, - typeQuit, - typePreferences, - typeAbout, - typeSeparator, -}; - -// we do NOT want programmatic updates to raise an ::activated signal -static void singleSetChecked(GtkCheckMenuItem *menuitem, gboolean checked, gulong signal) -{ - g_signal_handler_block(menuitem, signal); - gtk_check_menu_item_set_active(menuitem, checked); - g_signal_handler_unblock(menuitem, signal); -} - -static void setChecked(uiMenuItem *item, gboolean checked) -{ - GHashTableIter iter; - gpointer widget; - gpointer ww; - struct menuItemWindow *w; - - item->checked = checked; - g_hash_table_iter_init(&iter, item->windows); - while (g_hash_table_iter_next(&iter, &widget, &ww)) { - w = (struct menuItemWindow *) ww; - singleSetChecked(GTK_CHECK_MENU_ITEM(widget), item->checked, w->signal); - } -} - -static void onClicked(GtkMenuItem *menuitem, gpointer data) -{ - uiMenuItem *item = uiMenuItem(data); - struct menuItemWindow *w; - - // we need to manually update the checked states of all menu items if one changes - // notice that this is getting the checked state of the menu item that this signal is sent from - if (item->type == typeCheckbox) - setChecked(item, gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))); - - w = (struct menuItemWindow *) g_hash_table_lookup(item->windows, menuitem); - (*(item->onClicked))(item, w->w, item->onClickedData); -} - -static void defaultOnClicked(uiMenuItem *item, uiWindow *w, void *data) -{ - // do nothing -} - -static void onQuitClicked(uiMenuItem *item, uiWindow *w, void *data) -{ - if (shouldQuit()) - uiQuit(); -} - -static void menuItemEnableDisable(uiMenuItem *item, gboolean enabled) -{ - GHashTableIter iter; - gpointer widget; - - item->disabled = !enabled; - g_hash_table_iter_init(&iter, item->windows); - while (g_hash_table_iter_next(&iter, &widget, NULL)) - gtk_widget_set_sensitive(GTK_WIDGET(widget), enabled); -} - -void uiMenuItemEnable(uiMenuItem *item) -{ - menuItemEnableDisable(item, TRUE); -} - -void uiMenuItemDisable(uiMenuItem *item) -{ - menuItemEnableDisable(item, FALSE); -} - -void uiMenuItemOnClicked(uiMenuItem *item, void (*f)(uiMenuItem *, uiWindow *, void *), void *data) -{ - if (item->type == typeQuit) - userbug("You cannot call uiMenuItemOnClicked() on a Quit item; use uiOnShouldQuit() instead."); - item->onClicked = f; - item->onClickedData = data; -} - -int uiMenuItemChecked(uiMenuItem *item) -{ - return item->checked != FALSE; -} - -void uiMenuItemSetChecked(uiMenuItem *item, int checked) -{ - gboolean c; - - // use explicit values - c = FALSE; - if (checked) - c = TRUE; - setChecked(item, c); -} - -static uiMenuItem *newItem(uiMenu *m, int type, const char *name) -{ - uiMenuItem *item; - - if (menusFinalized) - userbug("You cannot create a new menu item after menus have been finalized."); - - item = uiNew(uiMenuItem); - - g_array_append_val(m->items, item); - - item->type = type; - switch (item->type) { - case typeQuit: - item->name = g_strdup("Quit"); - break; - case typePreferences: - item->name = g_strdup("Preferences..."); - break; - case typeAbout: - item->name = g_strdup("About"); - break; - case typeSeparator: - break; - default: - item->name = g_strdup(name); - break; - } - - if (item->type == typeQuit) { - // can't call uiMenuItemOnClicked() here - item->onClicked = onQuitClicked; - item->onClickedData = NULL; - } else - uiMenuItemOnClicked(item, defaultOnClicked, NULL); - - switch (item->type) { - case typeCheckbox: - item->gtype = GTK_TYPE_CHECK_MENU_ITEM; - break; - case typeSeparator: - item->gtype = GTK_TYPE_SEPARATOR_MENU_ITEM; - break; - default: - item->gtype = GTK_TYPE_MENU_ITEM; - break; - } - - item->windows = g_hash_table_new(g_direct_hash, g_direct_equal); - - return item; -} - -uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name) -{ - return newItem(m, typeRegular, name); -} - -uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name) -{ - return newItem(m, typeCheckbox, name); -} - -uiMenuItem *uiMenuAppendQuitItem(uiMenu *m) -{ - if (hasQuit) - userbug("You cannot have multiple Quit menu items in the same program."); - hasQuit = TRUE; - newItem(m, typeSeparator, NULL); - return newItem(m, typeQuit, NULL); -} - -uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m) -{ - if (hasPreferences) - userbug("You cannot have multiple Preferences menu items in the same program."); - hasPreferences = TRUE; - newItem(m, typeSeparator, NULL); - return newItem(m, typePreferences, NULL); -} - -uiMenuItem *uiMenuAppendAboutItem(uiMenu *m) -{ - if (hasAbout) - userbug("You cannot have multiple About menu items in the same program."); - hasAbout = TRUE; - newItem(m, typeSeparator, NULL); - return newItem(m, typeAbout, NULL); -} - -void uiMenuAppendSeparator(uiMenu *m) -{ - newItem(m, typeSeparator, NULL); -} - -uiMenu *uiNewMenu(const char *name) -{ - uiMenu *m; - - if (menusFinalized) - userbug("You cannot create a new menu after menus have been finalized."); - if (menus == NULL) - menus = g_array_new(FALSE, TRUE, sizeof (uiMenu *)); - - m = uiNew(uiMenu); - - g_array_append_val(menus, m); - - m->name = g_strdup(name); - m->items = g_array_new(FALSE, TRUE, sizeof (uiMenuItem *)); - - return m; -} - -static void appendMenuItem(GtkMenuShell *submenu, uiMenuItem *item, uiWindow *w) -{ - GtkWidget *menuitem; - gulong signal; - struct menuItemWindow *ww; - - menuitem = g_object_new(item->gtype, NULL); - if (item->name != NULL) - gtk_menu_item_set_label(GTK_MENU_ITEM(menuitem), item->name); - if (item->type != typeSeparator) { - signal = g_signal_connect(menuitem, "activate", G_CALLBACK(onClicked), item); - gtk_widget_set_sensitive(menuitem, !item->disabled); - if (item->type == typeCheckbox) - singleSetChecked(GTK_CHECK_MENU_ITEM(menuitem), item->checked, signal); - } - gtk_menu_shell_append(submenu, menuitem); - ww = uiNew(struct menuItemWindow); - ww->w = w; - ww->signal = signal; - g_hash_table_insert(item->windows, menuitem, ww); -} - -GtkWidget *makeMenubar(uiWindow *w) -{ - GtkWidget *menubar; - guint i, j; - uiMenu *m; - GtkWidget *menuitem; - GtkWidget *submenu; - - menusFinalized = TRUE; - - menubar = gtk_menu_bar_new(); - - if (menus != NULL) - for (i = 0; i < menus->len; i++) { - m = g_array_index(menus, uiMenu *, i); - menuitem = gtk_menu_item_new_with_label(m->name); - submenu = gtk_menu_new(); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); - for (j = 0; j < m->items->len; j++) - appendMenuItem(GTK_MENU_SHELL(submenu), g_array_index(m->items, uiMenuItem *, j), w); - gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menuitem); - } - - gtk_widget_set_hexpand(menubar, TRUE); - gtk_widget_set_halign(menubar, GTK_ALIGN_FILL); - return menubar; -} - -struct freeMenuItemData { - GArray *items; - guint i; -}; - -static void freeMenuItem(GtkWidget *widget, gpointer data) -{ - struct freeMenuItemData *fmi = (struct freeMenuItemData *) data; - uiMenuItem *item; - struct menuItemWindow *w; - - item = g_array_index(fmi->items, uiMenuItem *, fmi->i); - w = (struct menuItemWindow *) g_hash_table_lookup(item->windows, widget); - if (g_hash_table_remove(item->windows, widget) == FALSE) - implbug("GtkMenuItem %p not in menu item's item/window map", widget); - uiFree(w); - fmi->i++; -} - -static void freeMenu(GtkWidget *widget, gpointer data) -{ - guint *i = (guint *) data; - uiMenu *m; - GtkMenuItem *item; - GtkWidget *submenu; - struct freeMenuItemData fmi; - - m = g_array_index(menus, uiMenu *, *i); - item = GTK_MENU_ITEM(widget); - submenu = gtk_menu_item_get_submenu(item); - fmi.items = m->items; - fmi.i = 0; - gtk_container_foreach(GTK_CONTAINER(submenu), freeMenuItem, &fmi); - (*i)++; -} - -void freeMenubar(GtkWidget *mb) -{ - guint i; - - i = 0; - gtk_container_foreach(GTK_CONTAINER(mb), freeMenu, &i); - // no need to worry about destroying any widgets; destruction of the window they're in will do it for us -} - -void uninitMenus(void) -{ - uiMenu *m; - uiMenuItem *item; - guint i, j; - - if (menus == NULL) - return; - for (i = 0; i < menus->len; i++) { - m = g_array_index(menus, uiMenu *, i); - g_free(m->name); - for (j = 0; j < m->items->len; j++) { - item = g_array_index(m->items, uiMenuItem *, j); - if (g_hash_table_size(item->windows) != 0) - // TODO is this really a userbug()? - implbug("menu item %p (%s) still has uiWindows attached; did you forget to destroy some windows?", item, item->name); - g_free(item->name); - g_hash_table_destroy(item->windows); - uiFree(item); - } - g_array_free(m->items, TRUE); - uiFree(m); - } - g_array_free(menus, TRUE); -} diff --git a/deps/libui/unix/multilineentry.c b/deps/libui/unix/multilineentry.c deleted file mode 100644 index 09ffd46014..0000000000 --- a/deps/libui/unix/multilineentry.c +++ /dev/null @@ -1,124 +0,0 @@ -// 6 december 2015 -#include "uipriv_unix.h" - -struct uiMultilineEntry { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *scontainer; - GtkScrolledWindow *sw; - GtkWidget *textviewWidget; - GtkTextView *textview; - GtkTextBuffer *textbuf; - void (*onChanged)(uiMultilineEntry *, void *); - void *onChangedData; - gulong onChangedSignal; -}; - -uiUnixControlAllDefaults(uiMultilineEntry) - -static void onChanged(GtkTextBuffer *textbuf, gpointer data) -{ - uiMultilineEntry *e = uiMultilineEntry(data); - - (*(e->onChanged))(e, e->onChangedData); -} - -static void defaultOnChanged(uiMultilineEntry *e, void *data) -{ - // do nothing -} - -char *uiMultilineEntryText(uiMultilineEntry *e) -{ - GtkTextIter start, end; - char *tret, *out; - - gtk_text_buffer_get_start_iter(e->textbuf, &start); - gtk_text_buffer_get_end_iter(e->textbuf, &end); - tret = gtk_text_buffer_get_text(e->textbuf, &start, &end, TRUE); - // theoretically we could just return tret because uiUnixStrdupText() is just g_strdup(), but if that ever changes we can't, so let's do it this way to be safe - out = uiUnixStrdupText(tret); - g_free(tret); - return out; -} - -void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text) -{ - // we need to inhibit sending of ::changed because this WILL send a ::changed otherwise - g_signal_handler_block(e->textbuf, e->onChangedSignal); - gtk_text_buffer_set_text(e->textbuf, text, -1); - g_signal_handler_unblock(e->textbuf, e->onChangedSignal); -} - -// TODO scroll to end? -void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text) -{ - GtkTextIter end; - - gtk_text_buffer_get_end_iter(e->textbuf, &end); - // we need to inhibit sending of ::changed because this WILL send a ::changed otherwise - g_signal_handler_block(e->textbuf, e->onChangedSignal); - gtk_text_buffer_insert(e->textbuf, &end, text, -1); - g_signal_handler_unblock(e->textbuf, e->onChangedSignal); -} - -void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *e, void *data), void *data) -{ - e->onChanged = f; - e->onChangedData = data; -} - -int uiMultilineEntryReadOnly(uiMultilineEntry *e) -{ - return gtk_text_view_get_editable(e->textview) == FALSE; -} - -void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly) -{ - gboolean editable; - - editable = TRUE; - if (readonly) - editable = FALSE; - gtk_text_view_set_editable(e->textview, editable); -} - -static uiMultilineEntry *finishMultilineEntry(GtkPolicyType hpolicy, GtkWrapMode wrapMode) -{ - uiMultilineEntry *e; - - uiUnixNewControl(uiMultilineEntry, e); - - e->widget = gtk_scrolled_window_new(NULL, NULL); - e->scontainer = GTK_CONTAINER(e->widget); - e->sw = GTK_SCROLLED_WINDOW(e->widget); - gtk_scrolled_window_set_policy(e->sw, - hpolicy, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(e->sw, GTK_SHADOW_IN); - - e->textviewWidget = gtk_text_view_new(); - e->textview = GTK_TEXT_VIEW(e->textviewWidget); - gtk_text_view_set_wrap_mode(e->textview, wrapMode); - - gtk_container_add(e->scontainer, e->textviewWidget); - // and make the text view visible; only the scrolled window's visibility is controlled by libui - gtk_widget_show(e->textviewWidget); - - e->textbuf = gtk_text_view_get_buffer(e->textview); - - e->onChangedSignal = g_signal_connect(e->textbuf, "changed", G_CALLBACK(onChanged), e); - uiMultilineEntryOnChanged(e, defaultOnChanged, NULL); - - return e; -} - -uiMultilineEntry *uiNewMultilineEntry(void) -{ - return finishMultilineEntry(GTK_POLICY_NEVER, GTK_WRAP_WORD); -} - -uiMultilineEntry *uiNewNonWrappingMultilineEntry(void) -{ - return finishMultilineEntry(GTK_POLICY_AUTOMATIC, GTK_WRAP_NONE); -} diff --git a/deps/libui/unix/progressbar.c b/deps/libui/unix/progressbar.c deleted file mode 100644 index 9b543b04ad..0000000000 --- a/deps/libui/unix/progressbar.c +++ /dev/null @@ -1,71 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiProgressBar { - uiUnixControl c; - GtkWidget *widget; - GtkProgressBar *pbar; - gboolean indeterminate; - guint pulser; -}; - -uiUnixControlAllDefaultsExceptDestroy(uiProgressBar) - -static void uiProgressBarDestroy(uiControl *c) -{ - uiProgressBar *p = uiProgressBar(c); - - // be sure to stop the timeout now - if (p->indeterminate) - g_source_remove(p->pulser); - g_object_unref(p->widget); - uiFreeControl(uiControl(p)); -} - -int uiProgressBarValue(uiProgressBar *p) -{ - if (p->indeterminate) - return -1; - return (int) (gtk_progress_bar_get_fraction(p->pbar) * 100); -} - -static gboolean pulse(void* data) -{ - uiProgressBar *p = uiProgressBar(data); - - gtk_progress_bar_pulse(p->pbar); - return TRUE; -} - -void uiProgressBarSetValue(uiProgressBar *p, int value) -{ - if (value == -1) { - if (!p->indeterminate) { - p->indeterminate = TRUE; - // TODO verify the timeout - p->pulser = g_timeout_add(100, pulse, p); - } - return; - } - if (p->indeterminate) { - p->indeterminate = FALSE; - g_source_remove(p->pulser); - } - - if (value < 0 || value > 100) - userbug("Value %d is out of range for a uiProgressBar.", value); - - gtk_progress_bar_set_fraction(p->pbar, ((gdouble) value) / 100); -} - -uiProgressBar *uiNewProgressBar(void) -{ - uiProgressBar *p; - - uiUnixNewControl(uiProgressBar, p); - - p->widget = gtk_progress_bar_new(); - p->pbar = GTK_PROGRESS_BAR(p->widget); - - return p; -} diff --git a/deps/libui/unix/radiobuttons.c b/deps/libui/unix/radiobuttons.c deleted file mode 100644 index da41107e8c..0000000000 --- a/deps/libui/unix/radiobuttons.c +++ /dev/null @@ -1,121 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -// on GTK+ a uiRadioButtons is a GtkBox with each of the GtkRadioButtons as children - -struct uiRadioButtons { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkBox *box; - GPtrArray *buttons; - void (*onSelected)(uiRadioButtons *, void *); - void *onSelectedData; - gboolean changing; -}; - -uiUnixControlAllDefaultsExceptDestroy(uiRadioButtons) - -static void defaultOnSelected(uiRadioButtons *r, void *data) -{ - // do nothing -} - -static void onToggled(GtkToggleButton *tb, gpointer data) -{ - uiRadioButtons *r = uiRadioButtons(data); - - // only care if a button is selected - if (!gtk_toggle_button_get_active(tb)) - return; - // ignore programmatic changes - if (r->changing) - return; - (*(r->onSelected))(r, r->onSelectedData); -} - -static void uiRadioButtonsDestroy(uiControl *c) -{ - uiRadioButtons *r = uiRadioButtons(c); - GtkWidget *b; - - while (r->buttons->len != 0) { - b = GTK_WIDGET(g_ptr_array_remove_index(r->buttons, 0)); - gtk_widget_destroy(b); - } - g_ptr_array_free(r->buttons, TRUE); - // and free ourselves - g_object_unref(r->widget); - uiFreeControl(uiControl(r)); -} - -void uiRadioButtonsAppend(uiRadioButtons *r, const char *text) -{ - GtkWidget *rb; - GtkRadioButton *previous; - - previous = NULL; - if (r->buttons->len > 0) - previous = GTK_RADIO_BUTTON(g_ptr_array_index(r->buttons, 0)); - rb = gtk_radio_button_new_with_label_from_widget(previous, text); - g_signal_connect(rb, "toggled", G_CALLBACK(onToggled), r); - gtk_container_add(r->container, rb); - g_ptr_array_add(r->buttons, rb); - gtk_widget_show(rb); -} - -int uiRadioButtonsSelected(uiRadioButtons *r) -{ - GtkToggleButton *tb; - guint i; - - for (i = 0; i < r->buttons->len; i++) { - tb = GTK_TOGGLE_BUTTON(g_ptr_array_index(r->buttons, i)); - if (gtk_toggle_button_get_active(tb)) - return i; - } - return -1; -} - -void uiRadioButtonsSetSelected(uiRadioButtons *r, int n) -{ - GtkToggleButton *tb; - gboolean active; - - active = TRUE; - // TODO this doesn't work - if (n == -1) { - n = uiRadioButtonsSelected(r); - if (n == -1) // no selection; keep it that way - return; - active = FALSE; - } - tb = GTK_TOGGLE_BUTTON(g_ptr_array_index(r->buttons, n)); - // this is easier than remembering all the signals - r->changing = TRUE; - gtk_toggle_button_set_active(tb, active); - r->changing = FALSE; -} - -void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data) -{ - r->onSelected = f; - r->onSelectedData = data; -} - -uiRadioButtons *uiNewRadioButtons(void) -{ - uiRadioButtons *r; - - uiUnixNewControl(uiRadioButtons, r); - - r->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - r->container = GTK_CONTAINER(r->widget); - r->box = GTK_BOX(r->widget); - - r->buttons = g_ptr_array_new(); - - uiRadioButtonsOnSelected(r, defaultOnSelected, NULL); - - return r; -} diff --git a/deps/libui/unix/separator.c b/deps/libui/unix/separator.c deleted file mode 100644 index 02c75da536..0000000000 --- a/deps/libui/unix/separator.c +++ /dev/null @@ -1,34 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiSeparator { - uiUnixControl c; - GtkWidget *widget; - GtkSeparator *separator; -}; - -uiUnixControlAllDefaults(uiSeparator) - -uiSeparator *uiNewHorizontalSeparator(void) -{ - uiSeparator *s; - - uiUnixNewControl(uiSeparator, s); - - s->widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); - s->separator = GTK_SEPARATOR(s->widget); - - return s; -} - -uiSeparator *uiNewVerticalSeparator(void) -{ - uiSeparator *s; - - uiUnixNewControl(uiSeparator, s); - - s->widget = gtk_separator_new(GTK_ORIENTATION_VERTICAL); - s->separator = GTK_SEPARATOR(s->widget); - - return s; -} diff --git a/deps/libui/unix/slider.c b/deps/libui/unix/slider.c deleted file mode 100644 index 7f0cc24a18..0000000000 --- a/deps/libui/unix/slider.c +++ /dev/null @@ -1,71 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiSlider { - uiUnixControl c; - GtkWidget *widget; - GtkRange *range; - GtkScale *scale; - void (*onChanged)(uiSlider *, void *); - void *onChangedData; - gulong onChangedSignal; -}; - -uiUnixControlAllDefaults(uiSlider) - -static void onChanged(GtkRange *range, gpointer data) -{ - uiSlider *s = uiSlider(data); - - (*(s->onChanged))(s, s->onChangedData); -} - -static void defaultOnChanged(uiSlider *s, void *data) -{ - // do nothing -} - -int uiSliderValue(uiSlider *s) -{ - return gtk_range_get_value(s->range); -} - -void uiSliderSetValue(uiSlider *s, int value) -{ - // we need to inhibit sending of ::value-changed because this WILL send a ::value-changed otherwise - g_signal_handler_block(s->range, s->onChangedSignal); - gtk_range_set_value(s->range, value); - g_signal_handler_unblock(s->range, s->onChangedSignal); -} - -void uiSliderOnChanged(uiSlider *s, void (*f)(uiSlider *, void *), void *data) -{ - s->onChanged = f; - s->onChangedData = data; -} - -uiSlider *uiNewSlider(int min, int max) -{ - uiSlider *s; - int temp; - - if (min >= max) { - temp = min; - min = max; - max = temp; - } - - uiUnixNewControl(uiSlider, s); - - s->widget = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, min, max, 1); - s->range = GTK_RANGE(s->widget); - s->scale = GTK_SCALE(s->widget); - - // ensure integers, just to be safe - gtk_scale_set_digits(s->scale, 0); - - s->onChangedSignal = g_signal_connect(s->scale, "value-changed", G_CALLBACK(onChanged), s); - uiSliderOnChanged(s, defaultOnChanged, NULL); - - return s; -} diff --git a/deps/libui/unix/spinbox.c b/deps/libui/unix/spinbox.c deleted file mode 100644 index 90a5d3c1db..0000000000 --- a/deps/libui/unix/spinbox.c +++ /dev/null @@ -1,72 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiSpinbox { - uiUnixControl c; - GtkWidget *widget; - GtkEntry *entry; - GtkSpinButton *spinButton; - void (*onChanged)(uiSpinbox *, void *); - void *onChangedData; - gulong onChangedSignal; -}; - -uiUnixControlAllDefaults(uiSpinbox) - -static void onChanged(GtkSpinButton *sb, gpointer data) -{ - uiSpinbox *s = uiSpinbox(data); - - (*(s->onChanged))(s, s->onChangedData); -} - -static void defaultOnChanged(uiSpinbox *s, void *data) -{ - // do nothing -} - -int uiSpinboxValue(uiSpinbox *s) -{ - return gtk_spin_button_get_value(s->spinButton); -} - -void uiSpinboxSetValue(uiSpinbox *s, int value) -{ - // we need to inhibit sending of ::value-changed because this WILL send a ::value-changed otherwise - g_signal_handler_block(s->spinButton, s->onChangedSignal); - // this clamps for us - gtk_spin_button_set_value(s->spinButton, (gdouble) value); - g_signal_handler_unblock(s->spinButton, s->onChangedSignal); -} - -void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *, void *), void *data) -{ - s->onChanged = f; - s->onChangedData = data; -} - -uiSpinbox *uiNewSpinbox(int min, int max) -{ - uiSpinbox *s; - int temp; - - if (min >= max) { - temp = min; - min = max; - max = temp; - } - - uiUnixNewControl(uiSpinbox, s); - - s->widget = gtk_spin_button_new_with_range(min, max, 1); - s->entry = GTK_ENTRY(s->widget); - s->spinButton = GTK_SPIN_BUTTON(s->widget); - - // ensure integers, just to be safe - gtk_spin_button_set_digits(s->spinButton, 0); - - s->onChangedSignal = g_signal_connect(s->spinButton, "value-changed", G_CALLBACK(onChanged), s); - uiSpinboxOnChanged(s, defaultOnChanged, NULL); - - return s; -} diff --git a/deps/libui/unix/stddialogs.c b/deps/libui/unix/stddialogs.c deleted file mode 100644 index 93302f75e8..0000000000 --- a/deps/libui/unix/stddialogs.c +++ /dev/null @@ -1,66 +0,0 @@ -// 26 june 2015 -#include "uipriv_unix.h" - -// LONGTERM figure out why, and describe, that this is the desired behavior -// LONGTERM also point out that font and color buttons also work like this - -#define windowWindow(w) (GTK_WINDOW(uiControlHandle(uiControl(w)))) - -static char *filedialog(GtkWindow *parent, GtkFileChooserAction mode, const gchar *confirm) -{ - GtkWidget *fcd; - GtkFileChooser *fc; - gint response; - char *filename; - - fcd = gtk_file_chooser_dialog_new(NULL, parent, mode, - "_Cancel", GTK_RESPONSE_CANCEL, - confirm, GTK_RESPONSE_ACCEPT, - NULL); - fc = GTK_FILE_CHOOSER(fcd); - gtk_file_chooser_set_local_only(fc, FALSE); - gtk_file_chooser_set_select_multiple(fc, FALSE); - gtk_file_chooser_set_show_hidden(fc, TRUE); - gtk_file_chooser_set_do_overwrite_confirmation(fc, TRUE); - gtk_file_chooser_set_create_folders(fc, TRUE); - response = gtk_dialog_run(GTK_DIALOG(fcd)); - if (response != GTK_RESPONSE_ACCEPT) { - gtk_widget_destroy(fcd); - return NULL; - } - filename = uiUnixStrdupText(gtk_file_chooser_get_filename(fc)); - gtk_widget_destroy(fcd); - return filename; -} - -char *uiOpenFile(uiWindow *parent) -{ - return filedialog(windowWindow(parent), GTK_FILE_CHOOSER_ACTION_OPEN, "_Open"); -} - -char *uiSaveFile(uiWindow *parent) -{ - return filedialog(windowWindow(parent), GTK_FILE_CHOOSER_ACTION_SAVE, "_Save"); -} - -static void msgbox(GtkWindow *parent, const char *title, const char *description, GtkMessageType type, GtkButtonsType buttons) -{ - GtkWidget *md; - - md = gtk_message_dialog_new(parent, GTK_DIALOG_MODAL, - type, buttons, - "%s", title); - gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(md), "%s", description); - gtk_dialog_run(GTK_DIALOG(md)); - gtk_widget_destroy(md); -} - -void uiMsgBox(uiWindow *parent, const char *title, const char *description) -{ - msgbox(windowWindow(parent), title, description, GTK_MESSAGE_OTHER, GTK_BUTTONS_OK); -} - -void uiMsgBoxError(uiWindow *parent, const char *title, const char *description) -{ - msgbox(windowWindow(parent), title, description, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK); -} diff --git a/deps/libui/unix/tab.c b/deps/libui/unix/tab.c deleted file mode 100644 index 552e0e31a5..0000000000 --- a/deps/libui/unix/tab.c +++ /dev/null @@ -1,97 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiTab { - uiUnixControl c; - - GtkWidget *widget; - GtkContainer *container; - GtkNotebook *notebook; - - GArray *pages; // []*struct child -}; - -uiUnixControlAllDefaultsExceptDestroy(uiTab) - -static void uiTabDestroy(uiControl *c) -{ - uiTab *t = uiTab(c); - guint i; - struct child *page; - - for (i = 0; i < t->pages->len; i++) { - page = g_array_index(t->pages, struct child *, i); - childDestroy(page); - } - g_array_free(t->pages, TRUE); - // and free ourselves - g_object_unref(t->widget); - uiFreeControl(uiControl(t)); -} - -void uiTabAppend(uiTab *t, const char *name, uiControl *child) -{ - uiTabInsertAt(t, name, t->pages->len, child); -} - -void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) -{ - struct child *page; - - // this will create a tab, because of gtk_container_add() - page = newChildWithBox(child, uiControl(t), t->container, 0); - - gtk_notebook_set_tab_label_text(t->notebook, childBox(page), name); - gtk_notebook_reorder_child(t->notebook, childBox(page), n); - - g_array_insert_val(t->pages, n, page); -} - -void uiTabDelete(uiTab *t, int n) -{ - struct child *page; - - page = g_array_index(t->pages, struct child *, n); - // this will remove the tab, because gtk_widget_destroy() calls gtk_container_remove() - childRemove(page); - g_array_remove_index(t->pages, n); -} - -int uiTabNumPages(uiTab *t) -{ - return t->pages->len; -} - -int uiTabMargined(uiTab *t, int n) -{ - struct child *page; - - page = g_array_index(t->pages, struct child *, n); - return childFlag(page); -} - -void uiTabSetMargined(uiTab *t, int n, int margined) -{ - struct child *page; - - page = g_array_index(t->pages, struct child *, n); - childSetFlag(page, margined); - childSetMargined(page, childFlag(page)); -} - -uiTab *uiNewTab(void) -{ - uiTab *t; - - uiUnixNewControl(uiTab, t); - - t->widget = gtk_notebook_new(); - t->container = GTK_CONTAINER(t->widget); - t->notebook = GTK_NOTEBOOK(t->widget); - - gtk_notebook_set_scrollable(t->notebook, TRUE); - - t->pages = g_array_new(FALSE, TRUE, sizeof (struct child *)); - - return t; -} diff --git a/deps/libui/unix/text.c b/deps/libui/unix/text.c deleted file mode 100644 index ad92738d4a..0000000000 --- a/deps/libui/unix/text.c +++ /dev/null @@ -1,12 +0,0 @@ -// 9 april 2015 -#include "uipriv_unix.h" - -char *uiUnixStrdupText(const char *t) -{ - return g_strdup(t); -} - -void uiFreeText(char *t) -{ - g_free(t); -} diff --git a/deps/libui/unix/uipriv_unix.h b/deps/libui/unix/uipriv_unix.h deleted file mode 100644 index 33ff1e3553..0000000000 --- a/deps/libui/unix/uipriv_unix.h +++ /dev/null @@ -1,65 +0,0 @@ -// 22 april 2015 -#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_40 -#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_40 -#define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_10 -#define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_10 -#include -#include -#include // see drawtext.c -#include -#include -#include -#include "../ui.h" -#include "../ui_unix.h" -#include "../common/uipriv.h" - -#define gtkXMargin 12 -#define gtkYMargin 12 -#define gtkXPadding 12 -#define gtkYPadding 6 - -// menu.c -extern GtkWidget *makeMenubar(uiWindow *); -extern void freeMenubar(GtkWidget *); -extern void uninitMenus(void); - -// alloc.c -extern void initAlloc(void); -extern void uninitAlloc(void); - -// util.c -extern void setMargined(GtkContainer *, int); - -// child.c -extern struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parentContainer); -extern struct child *newChildWithBox(uiControl *child, uiControl *parent, GtkContainer *parentContainer, int margined); -extern void childRemove(struct child *c); -extern void childDestroy(struct child *c); -extern GtkWidget *childWidget(struct child *c); -extern int childFlag(struct child *c); -extern void childSetFlag(struct child *c, int flag); -extern GtkWidget *childBox(struct child *c); -extern void childSetMargined(struct child *c, int margined); - -// draw.c -extern uiDrawContext *newContext(cairo_t *); -extern void freeContext(uiDrawContext *); - -// drawtext.c -extern uiDrawTextFont *mkTextFont(PangoFont *f, gboolean add); -extern PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc); - -// graphemes.c -extern ptrdiff_t *graphemes(const char *text, PangoContext *context); - -// image.c -/*TODO remove this*/typedef struct uiImage uiImage; -extern cairo_surface_t *imageAppropriateSurface(uiImage *i, GtkWidget *w); - -// cellrendererbutton.c -extern GtkCellRenderer *newCellRendererButton(void); - -// future.c -extern void loadFutures(void); -extern PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha); -extern gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name); diff --git a/deps/libui/unix/util.c b/deps/libui/unix/util.c deleted file mode 100644 index 7f4f43fb4a..0000000000 --- a/deps/libui/unix/util.c +++ /dev/null @@ -1,10 +0,0 @@ -// 18 april 2015 -#include "uipriv_unix.h" - -void setMargined(GtkContainer *c, int margined) -{ - if (margined) - gtk_container_set_border_width(c, gtkXMargin); - else - gtk_container_set_border_width(c, 0); -} diff --git a/deps/libui/unix/window.c b/deps/libui/unix/window.c deleted file mode 100644 index ea9ba370f4..0000000000 --- a/deps/libui/unix/window.c +++ /dev/null @@ -1,279 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiWindow { - uiUnixControl c; - - GtkWidget *widget; - GtkContainer *container; - GtkWindow *window; - - GtkWidget *vboxWidget; - GtkContainer *vboxContainer; - GtkBox *vbox; - - GtkWidget *childHolderWidget; - GtkContainer *childHolderContainer; - - GtkWidget *menubar; - - uiControl *child; - int margined; - - int (*onClosing)(uiWindow *, void *); - void *onClosingData; - void (*onContentSizeChanged)(uiWindow *, void *); - void *onContentSizeChangedData; - gboolean fullscreen; -}; - -static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data) -{ - uiWindow *w = uiWindow(data); - - // manually destroy the window ourselves; don't let the delete-event handler do it - if ((*(w->onClosing))(w, w->onClosingData)) - uiControlDestroy(uiControl(w)); - // don't continue to the default delete-event handler; we destroyed the window by now - return TRUE; -} - -static void onSizeAllocate(GtkWidget *widget, GdkRectangle *allocation, gpointer data) -{ - uiWindow *w = uiWindow(data); - - // TODO deal with spurious size-allocates - (*(w->onContentSizeChanged))(w, w->onContentSizeChangedData); -} - -static int defaultOnClosing(uiWindow *w, void *data) -{ - return 0; -} - -static void defaultOnPositionContentSizeChanged(uiWindow *w, void *data) -{ - // do nothing -} - -static void uiWindowDestroy(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - // first hide ourselves - gtk_widget_hide(w->widget); - // now destroy the child - if (w->child != NULL) { - uiControlSetParent(w->child, NULL); - uiUnixControlSetContainer(uiUnixControl(w->child), w->childHolderContainer, TRUE); - uiControlDestroy(w->child); - } - // now destroy the menus, if any - if (w->menubar != NULL) - freeMenubar(w->menubar); - gtk_widget_destroy(w->childHolderWidget); - gtk_widget_destroy(w->vboxWidget); - // and finally free ourselves - // use gtk_widget_destroy() instead of g_object_unref() because GTK+ has internal references (see #165) - gtk_widget_destroy(w->widget); - uiFreeControl(uiControl(w)); -} - -uiUnixControlDefaultHandle(uiWindow) - -uiControl *uiWindowParent(uiControl *c) -{ - return NULL; -} - -void uiWindowSetParent(uiControl *c, uiControl *parent) -{ - uiUserBugCannotSetParentOnToplevel("uiWindow"); -} - -static int uiWindowToplevel(uiControl *c) -{ - return 1; -} - -uiUnixControlDefaultVisible(uiWindow) - -static void uiWindowShow(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - // don't use gtk_widget_show_all() as that will show all children, regardless of user settings - // don't use gtk_widget_show(); that doesn't bring to front or give keyboard focus - // (gtk_window_present() does call gtk_widget_show() though) - gtk_window_present(w->window); -} - -uiUnixControlDefaultHide(uiWindow) -uiUnixControlDefaultEnabled(uiWindow) -uiUnixControlDefaultEnable(uiWindow) -uiUnixControlDefaultDisable(uiWindow) -// TODO? -uiUnixControlDefaultSetContainer(uiWindow) - -char *uiWindowTitle(uiWindow *w) -{ - return uiUnixStrdupText(gtk_window_get_title(w->window)); -} - -void uiWindowSetTitle(uiWindow *w, const char *title) -{ - gtk_window_set_title(w->window, title); -} - -void uiWindowContentSize(uiWindow *w, int *width, int *height) -{ - GtkAllocation allocation; - - gtk_widget_get_allocation(w->childHolderWidget, &allocation); - *width = allocation.width; - *height = allocation.height; -} - -void uiWindowSetContentSize(uiWindow *w, int width, int height) -{ - GtkAllocation childAlloc; - gint winWidth, winHeight; - - // we need to resize the child holder widget to the given size - // we can't resize that without running the event loop - // but we can do gtk_window_set_size() - // so how do we deal with the differences in sizes? - // simple arithmetic, of course! - - // from what I can tell, the return from gtk_widget_get_allocation(w->window) and gtk_window_get_size(w->window) will be the same - // this is not affected by Wayland and not affected by GTK+ builtin CSD - // so we can safely juse use them to get the real window size! - // since we're using gtk_window_resize(), use the latter - gtk_window_get_size(w->window, &winWidth, &winHeight); - - // now get the child holder widget's current allocation - gtk_widget_get_allocation(w->childHolderWidget, &childAlloc); - // and punch that out of the window size - winWidth -= childAlloc.width; - winHeight -= childAlloc.height; - - // now we just need to add the new size back in - winWidth += width; - winHeight += height; - // and set it - // this will not move the window in my tests, so we're good - gtk_window_resize(w->window, winWidth, winHeight); -} - -int uiWindowFullscreen(uiWindow *w) -{ - return w->fullscreen; -} - -// TODO use window-state-event to track -// TODO does this send an extra size changed? -// TODO what behavior do we want? -void uiWindowSetFullscreen(uiWindow *w, int fullscreen) -{ - w->fullscreen = fullscreen; - if (w->fullscreen) - gtk_window_fullscreen(w->window); - else - gtk_window_unfullscreen(w->window); -} - -void uiWindowOnContentSizeChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data) -{ - w->onContentSizeChanged = f; - w->onContentSizeChangedData = data; -} - -void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data) -{ - w->onClosing = f; - w->onClosingData = data; -} - -int uiWindowBorderless(uiWindow *w) -{ - return gtk_window_get_decorated(w->window) == FALSE; -} - -void uiWindowSetBorderless(uiWindow *w, int borderless) -{ - gtk_window_set_decorated(w->window, borderless == 0); -} - -// TODO save and restore expands and aligns -void uiWindowSetChild(uiWindow *w, uiControl *child) -{ - if (w->child != NULL) { - uiControlSetParent(w->child, NULL); - uiUnixControlSetContainer(uiUnixControl(w->child), w->childHolderContainer, TRUE); - } - w->child = child; - if (w->child != NULL) { - uiControlSetParent(w->child, uiControl(w)); - uiUnixControlSetContainer(uiUnixControl(w->child), w->childHolderContainer, FALSE); - } -} - -int uiWindowMargined(uiWindow *w) -{ - return w->margined; -} - -void uiWindowSetMargined(uiWindow *w, int margined) -{ - w->margined = margined; - setMargined(w->childHolderContainer, w->margined); -} - -uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) -{ - uiWindow *w; - - uiUnixNewControl(uiWindow, w); - - w->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); - w->container = GTK_CONTAINER(w->widget); - w->window = GTK_WINDOW(w->widget); - - gtk_window_set_title(w->window, title); - gtk_window_resize(w->window, width, height); - - w->vboxWidget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - w->vboxContainer = GTK_CONTAINER(w->vboxWidget); - w->vbox = GTK_BOX(w->vboxWidget); - - // set the vbox as the GtkWindow child - gtk_container_add(w->container, w->vboxWidget); - - if (hasMenubar) { - w->menubar = makeMenubar(uiWindow(w)); - gtk_container_add(w->vboxContainer, w->menubar); - } - - w->childHolderWidget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - w->childHolderContainer = GTK_CONTAINER(w->childHolderWidget); - gtk_widget_set_hexpand(w->childHolderWidget, TRUE); - gtk_widget_set_halign(w->childHolderWidget, GTK_ALIGN_FILL); - gtk_widget_set_vexpand(w->childHolderWidget, TRUE); - gtk_widget_set_valign(w->childHolderWidget, GTK_ALIGN_FILL); - gtk_container_add(w->vboxContainer, w->childHolderWidget); - - // show everything in the vbox, but not the GtkWindow itself - gtk_widget_show_all(w->vboxWidget); - - // and connect our events - g_signal_connect(w->widget, "delete-event", G_CALLBACK(onClosing), w); - g_signal_connect(w->childHolderWidget, "size-allocate", G_CALLBACK(onSizeAllocate), w); - uiWindowOnClosing(w, defaultOnClosing, NULL); - uiWindowOnContentSizeChanged(w, defaultOnPositionContentSizeChanged, NULL); - - // normally it's SetParent() that does this, but we can't call SetParent() on a uiWindow - // TODO we really need to clean this up, especially since see uiWindowDestroy() above - g_object_ref(w->widget); - - return w; -} diff --git a/deps/libui/windows/CMakeLists.txt b/deps/libui/windows/CMakeLists.txt deleted file mode 100644 index 4695eb4f6e..0000000000 --- a/deps/libui/windows/CMakeLists.txt +++ /dev/null @@ -1,91 +0,0 @@ -# 3 june 2016 - -list(APPEND _LIBUI_SOURCES - windows/alloc.cpp - windows/area.cpp - windows/areadraw.cpp - windows/areaevents.cpp - windows/areascroll.cpp - windows/areautil.cpp - windows/box.cpp - windows/button.cpp - windows/checkbox.cpp - windows/colorbutton.cpp - windows/colordialog.cpp - windows/combobox.cpp - windows/container.cpp - windows/control.cpp - windows/d2dscratch.cpp - windows/datetimepicker.cpp - windows/debug.cpp - windows/draw.cpp - windows/drawmatrix.cpp - windows/drawpath.cpp - windows/drawtext.cpp - windows/dwrite.cpp - windows/editablecombo.cpp - windows/entry.cpp - windows/events.cpp - windows/fontbutton.cpp - windows/fontdialog.cpp - windows/form.cpp - windows/graphemes.cpp - windows/grid.cpp - windows/group.cpp - windows/init.cpp - windows/label.cpp - windows/main.cpp - windows/menu.cpp - windows/multilineentry.cpp - windows/parent.cpp - windows/progressbar.cpp - windows/radiobuttons.cpp - windows/separator.cpp - windows/sizing.cpp - windows/slider.cpp - windows/spinbox.cpp - windows/stddialogs.cpp - windows/tab.cpp - windows/tabpage.cpp - windows/text.cpp - windows/utf16.cpp - windows/utilwin.cpp - windows/window.cpp - windows/winpublic.cpp - windows/winutil.cpp - windows/resources.rc -) -set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) - -list(APPEND _LIBUI_INCLUDEDIRS - windows -) -set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE) - -# Windows won't link resources in static libraries; we need to provide the libui.res file in this case. -set(_LIBUINAME libui PARENT_SCOPE) -if(NOT BUILD_SHARED_LIBS) - set(_LIBUI_STATIC_RES ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/libui.res PARENT_SCOPE) -endif() -macro(_handle_static) - # TODO this full path feels hacky - add_custom_command( - TARGET libui POST_BUILD - COMMAND - ${CMAKE_COMMAND} -E copy $/CMakeFiles/libui.dir/windows/resources.rc.* ${_LIBUI_STATIC_RES} - COMMENT "Copying libui.res") -endmacro() - -# notice that usp10 comes before gdi32 -# TODO prune this list -set(_LIBUI_LIBS - user32 kernel32 usp10 gdi32 comctl32 uxtheme msimg32 comdlg32 d2d1 dwrite ole32 oleaut32 oleacc uuid -PARENT_SCOPE) - -if(NOT MSVC) - if(BUILD_SHARED_LIBS) - message(FATAL_ERROR - "Sorry, but libui for Windows can currently only be built as a static library with MinGW. You will need to either build as a static library or switch to MSVC." - ) - endif() -endif() diff --git a/deps/libui/windows/_uipriv_migrate.hpp b/deps/libui/windows/_uipriv_migrate.hpp deleted file mode 100644 index 13d3670ea9..0000000000 --- a/deps/libui/windows/_uipriv_migrate.hpp +++ /dev/null @@ -1,61 +0,0 @@ - -// menu.c -extern HMENU makeMenubar(void); -extern const uiMenuItem *menuIDToItem(UINT_PTR); -extern void runMenuEvent(WORD, uiWindow *); -extern void freeMenubar(HMENU); -extern void uninitMenus(void); - -// draw.c -extern HRESULT initDraw(void); -extern void uninitDraw(void); -extern ID2D1HwndRenderTarget *makeHWNDRenderTarget(HWND hwnd); -extern uiDrawContext *newContext(ID2D1RenderTarget *); -extern void freeContext(uiDrawContext *); - -// dwrite.cpp -#ifdef __cplusplus -extern IDWriteFactory *dwfactory; -#endif -extern HRESULT initDrawText(void); -extern void uninitDrawText(void); -#ifdef __cplusplus -struct fontCollection { - IDWriteFontCollection *fonts; - WCHAR userLocale[LOCALE_NAME_MAX_LENGTH]; - int userLocaleSuccess; -}; -extern fontCollection *loadFontCollection(void); -extern WCHAR *fontCollectionFamilyName(fontCollection *fc, IDWriteFontFamily *family); -extern void fontCollectionFree(fontCollection *fc); -extern WCHAR *fontCollectionCorrectString(fontCollection *fc, IDWriteLocalizedStrings *names); -#endif - -// drawtext.cpp -#ifdef __cplusplus -extern uiDrawTextFont *mkTextFont(IDWriteFont *df, BOOL addRef, WCHAR *family, BOOL copyFamily, double size); -struct dwriteAttr { - uiDrawTextWeight weight; - uiDrawTextItalic italic; - uiDrawTextStretch stretch; - DWRITE_FONT_WEIGHT dweight; - DWRITE_FONT_STYLE ditalic; - DWRITE_FONT_STRETCH dstretch; -}; -extern void attrToDWriteAttr(struct dwriteAttr *attr); -extern void dwriteAttrToAttr(struct dwriteAttr *attr); -#endif - -// fontdialog.cpp -#ifdef __cplusplus -struct fontDialogParams { - IDWriteFont *font; - double size; - WCHAR *familyName; - WCHAR *styleName; -}; -extern BOOL showFontDialog(HWND parent, struct fontDialogParams *params); -extern void loadInitialFontDialogParams(struct fontDialogParams *params); -extern void destroyFontDialogParams(struct fontDialogParams *params); -extern WCHAR *fontDialogParamsToString(struct fontDialogParams *params); -#endif diff --git a/deps/libui/windows/alloc.cpp b/deps/libui/windows/alloc.cpp deleted file mode 100644 index eeee3ad4b1..0000000000 --- a/deps/libui/windows/alloc.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// 4 december 2014 -#include "uipriv_windows.hpp" - -typedef std::vector byteArray; - -static std::map heap; -static std::map types; - -void initAlloc(void) -{ - // do nothing -} - -void uninitAlloc(void) -{ - std::ostringstream oss; - std::string ossstr; // keep alive, just to be safe - - if (heap.size() == 0) - return; - for (const auto &alloc : heap) - // note the void * cast; otherwise it'll be treated as a string - oss << (void *) (alloc.first) << " " << types[alloc.second] << "\n"; - ossstr = oss.str(); - userbug("Some data was leaked; either you left a uiControl lying around or there's a bug in libui itself. Leaked data:\n%s", ossstr.c_str()); -} - -#define rawBytes(pa) (&((*pa)[0])) - -void *uiAlloc(size_t size, const char *type) -{ - byteArray *out; - - out = new byteArray(size, 0); - heap[rawBytes(out)] = out; - types[out] = type; - return rawBytes(out); -} - -void *uiRealloc(void *_p, size_t size, const char *type) -{ - uint8_t *p = (uint8_t *) _p; - byteArray *arr; - - if (p == NULL) - return uiAlloc(size, type); - arr = heap[p]; - arr->resize(size, 0); - heap.erase(p); - heap[rawBytes(arr)] = arr; - return rawBytes(arr); -} - -void uiFree(void *_p) -{ - uint8_t *p = (uint8_t *) _p; - - if (p == NULL) - implbug("attempt to uiFree(NULL)"); - types.erase(heap[p]); - delete heap[p]; - heap.erase(p); -} diff --git a/deps/libui/windows/area.cpp b/deps/libui/windows/area.cpp deleted file mode 100644 index ab69ff1523..0000000000 --- a/deps/libui/windows/area.cpp +++ /dev/null @@ -1,206 +0,0 @@ -// 8 september 2015 -#include "uipriv_windows.hpp" -#include "area.hpp" - -// TODO handle WM_DESTROY/WM_NCDESTROY -// TODO same for other Direct2D stuff -static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - uiArea *a; - CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; - RECT client; - WINDOWPOS *wp = (WINDOWPOS *) lParam; - LRESULT lResult; - - a = (uiArea *) GetWindowLongPtrW(hwnd, GWLP_USERDATA); - if (a == NULL) { - if (uMsg == WM_CREATE) { - a = (uiArea *) (cs->lpCreateParams); - // assign a->hwnd here so we can use it immediately - a->hwnd = hwnd; - SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) a); - } - // fall through to DefWindowProcW() anyway - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } - - // always recreate the render target if necessary - if (a->rt == NULL) - a->rt = makeHWNDRenderTarget(a->hwnd); - - if (areaDoDraw(a, uMsg, wParam, lParam, &lResult) != FALSE) - return lResult; - - if (uMsg == WM_WINDOWPOSCHANGED) { - if ((wp->flags & SWP_NOSIZE) != 0) - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - uiWindowsEnsureGetClientRect(a->hwnd, &client); - areaDrawOnResize(a, &client); - areaScrollOnResize(a, &client); - return 0; - } - - if (areaDoScroll(a, uMsg, wParam, lParam, &lResult) != FALSE) - return lResult; - if (areaDoEvents(a, uMsg, wParam, lParam, &lResult) != FALSE) - return lResult; - - // nothing done - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -// control implementation - -uiWindowsControlAllDefaults(uiArea) - -static void uiAreaMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - // TODO - *width = 0; - *height = 0; -} - -ATOM registerAreaClass(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = areaClass; - wc.lpfnWndProc = areaWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - // this is just to be safe; see the InvalidateRect() call in the WM_WINDOWPOSCHANGED handler for more details - wc.style = CS_HREDRAW | CS_VREDRAW; - return RegisterClassW(&wc); -} - -void unregisterArea(void) -{ - if (UnregisterClassW(areaClass, hInstance) == 0) - logLastError(L"error unregistering uiArea window class"); -} - -void uiAreaSetSize(uiArea *a, int width, int height) -{ - a->scrollWidth = width; - a->scrollHeight = height; - areaUpdateScroll(a); -} - -void uiAreaQueueRedrawAll(uiArea *a) -{ - // don't erase the background; we do that ourselves in doPaint() - invalidateRect(a->hwnd, NULL, FALSE); -} - -void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height) -{ - // TODO -} - -void uiAreaBeginUserWindowMove(uiArea *a) -{ - HWND toplevel; - - // TODO restrict execution - ReleaseCapture(); // TODO use properly and reset internal data structures - toplevel = parentToplevel(a->hwnd); - if (toplevel == NULL) { - // TODO - return; - } - // see http://stackoverflow.com/questions/40249940/how-do-i-initiate-a-user-mouse-driven-move-or-resize-for-custom-window-borders-o#40250654 - SendMessageW(toplevel, WM_SYSCOMMAND, - SC_MOVE | 2, 0); -} - -void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge) -{ - HWND toplevel; - WPARAM wParam; - - // TODO restrict execution - ReleaseCapture(); // TODO use properly and reset internal data structures - toplevel = parentToplevel(a->hwnd); - if (toplevel == NULL) { - // TODO - return; - } - // see http://stackoverflow.com/questions/40249940/how-do-i-initiate-a-user-mouse-driven-move-or-resize-for-custom-window-borders-o#40250654 - wParam = SC_SIZE; - switch (edge) { - case uiWindowResizeEdgeLeft: - wParam |= 1; - break; - case uiWindowResizeEdgeTop: - wParam |= 3; - break; - case uiWindowResizeEdgeRight: - wParam |= 2; - break; - case uiWindowResizeEdgeBottom: - wParam |= 6; - break; - case uiWindowResizeEdgeTopLeft: - wParam |= 4; - break; - case uiWindowResizeEdgeTopRight: - wParam |= 5; - break; - case uiWindowResizeEdgeBottomLeft: - wParam |= 7; - break; - case uiWindowResizeEdgeBottomRight: - wParam |= 8; - break; - } - SendMessageW(toplevel, WM_SYSCOMMAND, - wParam, 0); -} - -uiArea *uiNewArea(uiAreaHandler *ah) -{ - uiArea *a; - - uiWindowsNewControl(uiArea, a); - - a->ah = ah; - a->scrolling = FALSE; - clickCounterReset(&(a->cc)); - - // a->hwnd is assigned in areaWndProc() - uiWindowsEnsureCreateControlHWND(0, - areaClass, L"", - 0, - hInstance, a, - FALSE); - - return a; -} - -uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height) -{ - uiArea *a; - - uiWindowsNewControl(uiArea, a); - - a->ah = ah; - a->scrolling = TRUE; - a->scrollWidth = width; - a->scrollHeight = height; - clickCounterReset(&(a->cc)); - - // a->hwnd is assigned in areaWndProc() - uiWindowsEnsureCreateControlHWND(0, - areaClass, L"", - WS_HSCROLL | WS_VSCROLL, - hInstance, a, - FALSE); - - // set initial scrolling parameters - areaUpdateScroll(a); - - return a; -} diff --git a/deps/libui/windows/area.hpp b/deps/libui/windows/area.hpp deleted file mode 100644 index 86a62de659..0000000000 --- a/deps/libui/windows/area.hpp +++ /dev/null @@ -1,45 +0,0 @@ -// 18 december 2015 - -// TODOs -// - things look very wrong on initial draw -// - initial scrolling is not set properly -// - should background be inherited from parent control? - -struct uiArea { - uiWindowsControl c; - HWND hwnd; - uiAreaHandler *ah; - - BOOL scrolling; - int scrollWidth; - int scrollHeight; - int hscrollpos; - int vscrollpos; - int hwheelCarry; - int vwheelCarry; - - clickCounter cc; - BOOL capturing; - - BOOL inside; - BOOL tracking; - - ID2D1HwndRenderTarget *rt; -}; - -// areadraw.cpp -extern BOOL areaDoDraw(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult); -extern void areaDrawOnResize(uiArea *, RECT *); - -// areascroll.cpp -extern BOOL areaDoScroll(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult); -extern void areaScrollOnResize(uiArea *, RECT *); -extern void areaUpdateScroll(uiArea *a); - -// areaevents.cpp -extern BOOL areaDoEvents(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult); - -// areautil.cpp -extern void loadAreaSize(uiArea *a, ID2D1RenderTarget *rt, double *width, double *height); -extern void pixelsToDIP(uiArea *a, double *x, double *y); -extern void dipToPixels(uiArea *a, double *x, double *y); diff --git a/deps/libui/windows/areadraw.cpp b/deps/libui/windows/areadraw.cpp deleted file mode 100644 index 7b3dc69600..0000000000 --- a/deps/libui/windows/areadraw.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// 8 september 2015 -#include "uipriv_windows.hpp" -#include "area.hpp" - -static HRESULT doPaint(uiArea *a, ID2D1RenderTarget *rt, RECT *clip) -{ - uiAreaHandler *ah = a->ah; - uiAreaDrawParams dp; - COLORREF bgcolorref; - D2D1_COLOR_F bgcolor; - D2D1_MATRIX_3X2_F scrollTransform; - - // no need to save or restore the graphics state to reset transformations; it's handled by resetTarget() in draw.c, called during the following - dp.Context = newContext(rt); - - loadAreaSize(a, rt, &(dp.AreaWidth), &(dp.AreaHeight)); - - dp.ClipX = clip->left; - dp.ClipY = clip->top; - dp.ClipWidth = clip->right - clip->left; - dp.ClipHeight = clip->bottom - clip->top; - if (a->scrolling) { - dp.ClipX += a->hscrollpos; - dp.ClipY += a->vscrollpos; - } - - rt->BeginDraw(); - - if (a->scrolling) { - ZeroMemory(&scrollTransform, sizeof (D2D1_MATRIX_3X2_F)); - scrollTransform._11 = 1; - scrollTransform._22 = 1; - // negative because we want nonzero scroll positions to move the drawing area up/left - scrollTransform._31 = -a->hscrollpos; - scrollTransform._32 = -a->vscrollpos; - rt->SetTransform(&scrollTransform); - } - - // TODO push axis aligned clip - - // TODO only clear the clip area - // TODO clear with actual background brush - bgcolorref = GetSysColor(COLOR_BTNFACE); - bgcolor.r = ((float) GetRValue(bgcolorref)) / 255.0; - // due to utter apathy on Microsoft's part, GetGValue() does not work with MSVC's Run-Time Error Checks - // it has not worked since 2008 and they have *never* fixed it - // TODO now that -RTCc has just been deprecated entirely, should we switch back? - bgcolor.g = ((float) ((BYTE) ((bgcolorref & 0xFF00) >> 8))) / 255.0; - bgcolor.b = ((float) GetBValue(bgcolorref)) / 255.0; - bgcolor.a = 1.0; - rt->Clear(&bgcolor); - - (*(ah->Draw))(ah, a, &dp); - - freeContext(dp.Context); - - // TODO pop axis aligned clip - - return rt->EndDraw(NULL, NULL); -} - -static void onWM_PAINT(uiArea *a) -{ - RECT clip; - HRESULT hr; - - // do not clear the update rect; we do that ourselves in doPaint() - if (GetUpdateRect(a->hwnd, &clip, FALSE) == 0) { - // set a zero clip rect just in case GetUpdateRect() didn't change clip - clip.left = 0; - clip.top = 0; - clip.right = 0; - clip.bottom = 0; - } - hr = doPaint(a, a->rt, &clip); - switch (hr) { - case S_OK: - if (ValidateRect(a->hwnd, NULL) == 0) - logLastError(L"error validating rect"); - break; - case D2DERR_RECREATE_TARGET: - // DON'T validate the rect - // instead, simply drop the render target - // we'll get another WM_PAINT and make the render target again - // TODO would this require us to invalidate the entire client area? - a->rt->Release();; - a->rt = NULL; - break; - default: - logHRESULT(L"error painting", hr); - } -} - -static void onWM_PRINTCLIENT(uiArea *a, HDC dc) -{ - ID2D1DCRenderTarget *rt; - RECT client; - HRESULT hr; - - uiWindowsEnsureGetClientRect(a->hwnd, &client); - rt = makeHDCRenderTarget(dc, &client); - hr = doPaint(a, rt, &client); - if (hr != S_OK) - logHRESULT(L"error printing uiArea client area", hr); - rt->Release(); -} - -BOOL areaDoDraw(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult) -{ - switch (uMsg) { - case WM_PAINT: - onWM_PAINT(a); - *lResult = 0; - return TRUE; - case WM_PRINTCLIENT: - onWM_PRINTCLIENT(a, (HDC) wParam); - *lResult = 0; - return TRUE; - } - return FALSE; -} - -// TODO only if the render target wasn't just created? -void areaDrawOnResize(uiArea *a, RECT *newClient) -{ - D2D1_SIZE_U size; - - size.width = newClient->right - newClient->left; - size.height = newClient->bottom - newClient->top; - // don't track the error; we'll get that in EndDraw() - // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd370994%28v=vs.85%29.aspx - a->rt->Resize(&size); - - // according to Rick Brewster, we must always redraw the entire client area after calling ID2D1RenderTarget::Resize() (see http://stackoverflow.com/a/33222983/3408572) - // we used to have a uiAreaHandler.RedrawOnResize() method to decide this; now you know why we don't anymore - invalidateRect(a->hwnd, NULL, TRUE); -} diff --git a/deps/libui/windows/areaevents.cpp b/deps/libui/windows/areaevents.cpp deleted file mode 100644 index 7d391b853b..0000000000 --- a/deps/libui/windows/areaevents.cpp +++ /dev/null @@ -1,421 +0,0 @@ -// 8 september 2015 -#include "uipriv_windows.hpp" -#include "area.hpp" - -static uiModifiers getModifiers(void) -{ - uiModifiers m = 0; - - if ((GetKeyState(VK_CONTROL) & 0x80) != 0) - m |= uiModifierCtrl; - if ((GetKeyState(VK_MENU) & 0x80) != 0) - m |= uiModifierAlt; - if ((GetKeyState(VK_SHIFT) & 0x80) != 0) - m |= uiModifierShift; - if ((GetKeyState(VK_LWIN) & 0x80) != 0) - m |= uiModifierSuper; - if ((GetKeyState(VK_RWIN) & 0x80) != 0) - m |= uiModifierSuper; - return m; -} - -/* -Windows doesn't natively support mouse crossing events. - -TrackMouseEvent() (and its comctl32.dll wrapper _TrackMouseEvent()) both allow for a window to receive the WM_MOUSELEAVE message when the mouse leaves the client area. There's no equivalent WM_MOUSEENTER because it can be simulated (https://blogs.msdn.microsoft.com/oldnewthing/20031013-00/?p=42193). - -Unfortunately, WM_MOUSELEAVE does not get generated while the mouse is captured. We need to capture for drag behavior to work properly, so this isn't going to mix well. - -So what we do: -- on WM_MOUSEMOVE, if we don't have the capture, start tracking - - this will handle the case of the capture being released while still in the area -- on WM_MOUSELEAVE, mark that we are no longer tracking - - Windows has already done the work of that for us; it's just a flag we use for the next part -- when starting capture, stop tracking if we are tracking -- if capturing, manually check if the pointer is in the client rect on each area event -*/ -static void track(uiArea *a, BOOL tracking) -{ - TRACKMOUSEEVENT tm; - - // do nothing if there's no change - if (a->tracking && tracking) - return; - if (!a->tracking && !tracking) - return; - - a->tracking = tracking; - ZeroMemory(&tm, sizeof (TRACKMOUSEEVENT)); - tm.cbSize = sizeof (TRACKMOUSEEVENT); - tm.dwFlags = TME_LEAVE; - if (!a->tracking) - tm.dwFlags |= TME_CANCEL; - tm.hwndTrack = a->hwnd; - if (_TrackMouseEvent(&tm) == 0) - logLastError(L"error setting up mouse tracking"); -} - -static void capture(uiArea *a, BOOL capturing) -{ - // do nothing if there's no change - if (a->capturing && capturing) - return; - if (!a->capturing && !capturing) - return; - - // change flag first as ReleaseCapture() sends WM_CAPTURECHANGED - a->capturing = capturing; - if (a->capturing) { - track(a, FALSE); - SetCapture(a->hwnd); - } else - if (ReleaseCapture() == 0) - logLastError(L"error releasing capture on drag"); -} - -static void areaMouseEvent(uiArea *a, int down, int up, WPARAM wParam, LPARAM lParam) -{ - uiAreaMouseEvent me; - int button; - POINT clientpt; - RECT client; - BOOL inClient; - double xpix, ypix; - - if (a->capturing) { - clientpt.x = GET_X_LPARAM(lParam); - clientpt.y = GET_Y_LPARAM(lParam); - uiWindowsEnsureGetClientRect(a->hwnd, &client); - inClient = PtInRect(&client, clientpt); - if (inClient && !a->inside) { - a->inside = TRUE; - (*(a->ah->MouseCrossed))(a->ah, a, 0); - clickCounterReset(&(a->cc)); - } else if (!inClient && a->inside) { - a->inside = FALSE; - (*(a->ah->MouseCrossed))(a->ah, a, 1); - clickCounterReset(&(a->cc)); - } - } - - xpix = (double) GET_X_LPARAM(lParam); - ypix = (double) GET_Y_LPARAM(lParam); - // these are in pixels; we need points - pixelsToDIP(a, &xpix, &ypix); - me.X = xpix; - me.Y = ypix; - if (a->scrolling) { - me.X += a->hscrollpos; - me.Y += a->vscrollpos; - } - - loadAreaSize(a, NULL, &(me.AreaWidth), &(me.AreaHeight)); - - me.Down = down; - me.Up = up; - me.Count = 0; - if (me.Down != 0) - // GetMessageTime() returns LONG and GetDoubleClckTime() returns UINT, which are int32 and uint32, respectively, but we don't need to worry about the signedness because for the same bit widths and two's complement arithmetic, s1-s2 == u1-u2 if bits(s1)==bits(s2) and bits(u1)==bits(u2) (and Windows requires two's complement: http://blogs.msdn.com/b/oldnewthing/archive/2005/05/27/422551.aspx) - // signedness isn't much of an issue for these calls anyway because http://stackoverflow.com/questions/24022225/what-are-the-sign-extension-rules-for-calling-windows-api-functions-stdcall-t and that we're only using unsigned values (think back to how you (didn't) handle signedness in assembly language) AND because of the above AND because the statistics below (time interval and width/height) really don't make sense if negative - // GetSystemMetrics() returns int, which is int32 - me.Count = clickCounterClick(&(a->cc), me.Down, - me.X, me.Y, - GetMessageTime(), GetDoubleClickTime(), - GetSystemMetrics(SM_CXDOUBLECLK) / 2, - GetSystemMetrics(SM_CYDOUBLECLK) / 2); - - // though wparam will contain control and shift state, let's just one function to get modifiers for both keyboard and mouse events; it'll work the same anyway since we have to do this for alt and windows key (super) - me.Modifiers = getModifiers(); - - button = me.Down; - if (button == 0) - button = me.Up; - me.Held1To64 = 0; - if (button != 1 && (wParam & MK_LBUTTON) != 0) - me.Held1To64 |= 1 << 0; - if (button != 2 && (wParam & MK_MBUTTON) != 0) - me.Held1To64 |= 1 << 1; - if (button != 3 && (wParam & MK_RBUTTON) != 0) - me.Held1To64 |= 1 << 2; - if (button != 4 && (wParam & MK_XBUTTON1) != 0) - me.Held1To64 |= 1 << 3; - if (button != 5 && (wParam & MK_XBUTTON2) != 0) - me.Held1To64 |= 1 << 4; - - // on Windows, we have to capture on drag ourselves - if (me.Down != 0) - capture(a, TRUE); - // only release capture when all buttons released - if (me.Up != 0 && me.Held1To64 == 0) - capture(a, FALSE); - - (*(a->ah->MouseEvent))(a->ah, a, &me); -} - -// TODO genericize this so it can be called above -static void onMouseEntered(uiArea *a) -{ - if (a->inside) - return; - if (a->capturing) // we handle mouse crossing in areaMouseEvent() - return; - track(a, TRUE); - (*(a->ah->MouseCrossed))(a->ah, a, 0); - // TODO figure out why we did this to begin with; either we do it on both GTK+ and Windows or not at all - clickCounterReset(&(a->cc)); -} - -// TODO genericize it so that it can be called above -static void onMouseLeft(uiArea *a) -{ - a->tracking = FALSE; - a->inside = FALSE; - (*(a->ah->MouseCrossed))(a->ah, a, 1); - // TODO figure out why we did this to begin with; either we do it on both GTK+ and Windows or not at all - clickCounterReset(&(a->cc)); -} - -// we use VK_SNAPSHOT as a sentinel because libui will never support the print screen key; that key belongs to the user -struct extkeymap { - WPARAM vk; - uiExtKey extkey; -}; - -// all mappings come from GLFW - https://github.com/glfw/glfw/blob/master/src/win32_window.c#L152 -static const struct extkeymap numpadExtKeys[] = { - { VK_HOME, uiExtKeyN7 }, - { VK_UP, uiExtKeyN8 }, - { VK_PRIOR, uiExtKeyN9 }, - { VK_LEFT, uiExtKeyN4 }, - { VK_CLEAR, uiExtKeyN5 }, - { VK_RIGHT, uiExtKeyN6 }, - { VK_END, uiExtKeyN1 }, - { VK_DOWN, uiExtKeyN2 }, - { VK_NEXT, uiExtKeyN3 }, - { VK_INSERT, uiExtKeyN0 }, - { VK_DELETE, uiExtKeyNDot }, - { VK_SNAPSHOT, 0 }, -}; - -static const struct extkeymap extKeys[] = { - { VK_ESCAPE, uiExtKeyEscape }, - { VK_INSERT, uiExtKeyInsert }, - { VK_DELETE, uiExtKeyDelete }, - { VK_HOME, uiExtKeyHome }, - { VK_END, uiExtKeyEnd }, - { VK_PRIOR, uiExtKeyPageUp }, - { VK_NEXT, uiExtKeyPageDown }, - { VK_UP, uiExtKeyUp }, - { VK_DOWN, uiExtKeyDown }, - { VK_LEFT, uiExtKeyLeft }, - { VK_RIGHT, uiExtKeyRight }, - { VK_F1, uiExtKeyF1 }, - { VK_F2, uiExtKeyF2 }, - { VK_F3, uiExtKeyF3 }, - { VK_F4, uiExtKeyF4 }, - { VK_F5, uiExtKeyF5 }, - { VK_F6, uiExtKeyF6 }, - { VK_F7, uiExtKeyF7 }, - { VK_F8, uiExtKeyF8 }, - { VK_F9, uiExtKeyF9 }, - { VK_F10, uiExtKeyF10 }, - { VK_F11, uiExtKeyF11 }, - { VK_F12, uiExtKeyF12 }, - // numpad numeric keys and . are handled in common/areaevents.c - // numpad enter is handled in code below - { VK_ADD, uiExtKeyNAdd }, - { VK_SUBTRACT, uiExtKeyNSubtract }, - { VK_MULTIPLY, uiExtKeyNMultiply }, - { VK_DIVIDE, uiExtKeyNDivide }, - { VK_SNAPSHOT, 0 }, -}; - -static const struct { - WPARAM vk; - uiModifiers mod; -} modKeys[] = { - // even if the separate left/right aren't necessary, have them here anyway, just to be safe - { VK_CONTROL, uiModifierCtrl }, - { VK_LCONTROL, uiModifierCtrl }, - { VK_RCONTROL, uiModifierCtrl }, - { VK_MENU, uiModifierAlt }, - { VK_LMENU, uiModifierAlt }, - { VK_RMENU, uiModifierAlt }, - { VK_SHIFT, uiModifierShift }, - { VK_LSHIFT, uiModifierShift }, - { VK_RSHIFT, uiModifierShift }, - // there's no combined Windows key virtual-key code as there is with the others - { VK_LWIN, uiModifierSuper }, - { VK_RWIN, uiModifierSuper }, - { VK_SNAPSHOT, 0 }, -}; - -static int areaKeyEvent(uiArea *a, int up, WPARAM wParam, LPARAM lParam) -{ - uiAreaKeyEvent ke; - int righthand; - int i; - - ke.Key = 0; - ke.ExtKey = 0; - ke.Modifier = 0; - - ke.Modifiers = getModifiers(); - - ke.Up = up; - - // the numeric keypad keys when Num Lock is off are considered left-hand keys as the separate navigation buttons were added later - // the numeric keypad Enter, however, is a right-hand key because it has the same virtual-key code as the typewriter Enter - righthand = (lParam & 0x01000000) != 0; - if (righthand) { - if (wParam == VK_RETURN) { - ke.ExtKey = uiExtKeyNEnter; - goto keyFound; - } - } else - // this is special handling for numpad keys to ignore the state of Num Lock and Shift; see http://blogs.msdn.com/b/oldnewthing/archive/2004/09/06/226045.aspx and https://github.com/glfw/glfw/blob/master/src/win32_window.c#L152 - for (i = 0; numpadExtKeys[i].vk != VK_SNAPSHOT; i++) - if (numpadExtKeys[i].vk == wParam) { - ke.ExtKey = numpadExtKeys[i].extkey; - goto keyFound; - } - - // okay, those above cases didn't match anything - // first try the extended keys - for (i = 0; extKeys[i].vk != VK_SNAPSHOT; i++) - if (extKeys[i].vk == wParam) { - ke.ExtKey = extKeys[i].extkey; - goto keyFound; - } - - // then try modifier keys - for (i = 0; modKeys[i].vk != VK_SNAPSHOT; i++) - if (modKeys[i].vk == wParam) { - ke.Modifier = modKeys[i].mod; - // and don't include the key in Modifiers - ke.Modifiers &= ~ke.Modifier; - goto keyFound; - } - - // and finally everything else - if (fromScancode((lParam >> 16) & 0xFF, &ke)) - goto keyFound; - - // not a supported key, assume unhandled - // TODO the original code only did this if ke.Modifiers == 0 - why? - return 0; - -keyFound: - return (*(a->ah->KeyEvent))(a->ah, a, &ke); -} - -// We don't handle the standard Windows keyboard messages directly, to avoid both the dialog manager and TranslateMessage(). -// Instead, we set up a message filter and do things there. -// That stuff is later in this file. -enum { - // start at 0x40 to avoid clobbering dialog messages - msgAreaKeyDown = WM_USER + 0x40, - msgAreaKeyUp, -}; - -BOOL areaDoEvents(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult) -{ - switch (uMsg) { - case WM_ACTIVATE: - // don't keep the double-click timer running if the user switched programs in between clicks - clickCounterReset(&(a->cc)); - *lResult = 0; - return TRUE; - case WM_MOUSEMOVE: - onMouseEntered(a); - areaMouseEvent(a, 0, 0, wParam, lParam); - *lResult = 0; - return TRUE; - case WM_MOUSELEAVE: - onMouseLeft(a); - *lResult = 0; - return TRUE; - case WM_LBUTTONDOWN: - SetFocus(a->hwnd); - areaMouseEvent(a, 1, 0, wParam, lParam); - *lResult = 0; - return TRUE; - case WM_LBUTTONUP: - areaMouseEvent(a, 0, 1, wParam, lParam); - *lResult = 0; - return TRUE; - case WM_MBUTTONDOWN: - SetFocus(a->hwnd); - areaMouseEvent(a, 2, 0, wParam, lParam); - *lResult = 0; - return TRUE; - case WM_MBUTTONUP: - areaMouseEvent(a, 0, 2, wParam, lParam); - *lResult = 0; - return TRUE; - case WM_RBUTTONDOWN: - SetFocus(a->hwnd); - areaMouseEvent(a, 3, 0, wParam, lParam); - *lResult = 0; - return TRUE; - case WM_RBUTTONUP: - areaMouseEvent(a, 0, 3, wParam, lParam); - *lResult = 0; - return TRUE; - case WM_XBUTTONDOWN: - SetFocus(a->hwnd); - // values start at 1; we want them to start at 4 - areaMouseEvent(a, - GET_XBUTTON_WPARAM(wParam) + 3, 0, - GET_KEYSTATE_WPARAM(wParam), lParam); - *lResult = TRUE; // XBUTTON messages are different! - return TRUE; - case WM_XBUTTONUP: - areaMouseEvent(a, - 0, GET_XBUTTON_WPARAM(wParam) + 3, - GET_KEYSTATE_WPARAM(wParam), lParam); - *lResult = TRUE; // XBUTTON messages are different! - return TRUE; - case WM_CAPTURECHANGED: - if (a->capturing) { - a->capturing = FALSE; - (*(a->ah->DragBroken))(a->ah, a); - } - *lResult = 0; - return TRUE; - case msgAreaKeyDown: - *lResult = (LRESULT) areaKeyEvent(a, 0, wParam, lParam); - return TRUE; - case msgAreaKeyUp: - *lResult = (LRESULT) areaKeyEvent(a, 1, wParam, lParam); - return TRUE; - } - return FALSE; -} - -// TODO affect visibility properly -// TODO what did this mean -BOOL areaFilter(MSG *msg) -{ - LRESULT handled; - - // is the recipient an area? - if (msg->hwnd == NULL) // this can happen; for example, WM_TIMER - return FALSE; - if (windowClassOf(msg->hwnd, areaClass, NULL) != 0) - return FALSE; // nope - - handled = 0; - switch (msg->message) { - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - handled = SendMessageW(msg->hwnd, msgAreaKeyDown, msg->wParam, msg->lParam); - break; - case WM_KEYUP: - case WM_SYSKEYUP: - handled = SendMessageW(msg->hwnd, msgAreaKeyUp, msg->wParam, msg->lParam); - break; - // otherwise handled remains 0, as we didn't handle this - } - return (BOOL) handled; -} diff --git a/deps/libui/windows/areascroll.cpp b/deps/libui/windows/areascroll.cpp deleted file mode 100644 index f18d0ad874..0000000000 --- a/deps/libui/windows/areascroll.cpp +++ /dev/null @@ -1,247 +0,0 @@ -// 8 september 2015 -#include "uipriv_windows.hpp" -#include "area.hpp" - -// TODO -// - move from pixels to points somehow -// - add a function to offset points and rects by scrolling amounts; call it from doPaint() in areadraw.c -// - recalculate scrolling after: -// - creation? -// - resize? -// - recreating the render target? (after moving to points) -// - error if these are called without scrollbars? - -struct scrollParams { - int *pos; - int pagesize; - int length; - int *wheelCarry; - UINT wheelSPIAction; -}; - -static void scrollto(uiArea *a, int which, struct scrollParams *p, int pos) -{ - SCROLLINFO si; - - // note that the pos < 0 check is /after/ the p->length - p->pagesize check - // it used to be /before/; this was actually a bug in Raymond Chen's original algorithm: if there are fewer than a page's worth of items, p->length - p->pagesize will be negative and our content draw at the bottom of the window - // this SHOULD have the same effect with that bug fixed and no others introduced... (thanks to devin on irc.badnik.net for confirming this logic) - if (pos > p->length - p->pagesize) - pos = p->length - p->pagesize; - if (pos < 0) - pos = 0; - - // Direct2D doesn't have a method for scrolling the existing contents of a render target. - // We'll have to just invalidate everything and hope for the best. - invalidateRect(a->hwnd, NULL, FALSE); - - *(p->pos) = pos; - - // now commit our new scrollbar setup... - ZeroMemory(&si, sizeof (SCROLLINFO)); - si.cbSize = sizeof (SCROLLINFO); - si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; - si.nPage = p->pagesize; - si.nMin = 0; - si.nMax = p->length - 1; // endpoint inclusive - si.nPos = *(p->pos); - SetScrollInfo(a->hwnd, which, &si, TRUE); -} - -static void scrollby(uiArea *a, int which, struct scrollParams *p, int delta) -{ - scrollto(a, which, p, *(p->pos) + delta); -} - -static void scroll(uiArea *a, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam) -{ - int pos; - SCROLLINFO si; - - pos = *(p->pos); - switch (LOWORD(wParam)) { - case SB_LEFT: // also SB_TOP - pos = 0; - break; - case SB_RIGHT: // also SB_BOTTOM - pos = p->length - p->pagesize; - break; - case SB_LINELEFT: // also SB_LINEUP - pos--; - break; - case SB_LINERIGHT: // also SB_LINEDOWN - pos++; - break; - case SB_PAGELEFT: // also SB_PAGEUP - pos -= p->pagesize; - break; - case SB_PAGERIGHT: // also SB_PAGEDOWN - pos += p->pagesize; - break; - case SB_THUMBPOSITION: - ZeroMemory(&si, sizeof (SCROLLINFO)); - si.cbSize = sizeof (SCROLLINFO); - si.fMask = SIF_POS; - if (GetScrollInfo(a->hwnd, which, &si) == 0) - logLastError(L"error getting thumb position for area"); - pos = si.nPos; - break; - case SB_THUMBTRACK: - ZeroMemory(&si, sizeof (SCROLLINFO)); - si.cbSize = sizeof (SCROLLINFO); - si.fMask = SIF_TRACKPOS; - if (GetScrollInfo(a->hwnd, which, &si) == 0) - logLastError(L"error getting thumb track position for area"); - pos = si.nTrackPos; - break; - } - scrollto(a, which, p, pos); -} - -static void wheelscroll(uiArea *a, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam) -{ - int delta; - int lines; - UINT scrollAmount; - - delta = GET_WHEEL_DELTA_WPARAM(wParam); - if (SystemParametersInfoW(p->wheelSPIAction, 0, &scrollAmount, 0) == 0) - // TODO use scrollAmount == 3 (for both v and h) instead? - logLastError(L"error getting area wheel scroll amount"); - if (scrollAmount == WHEEL_PAGESCROLL) - scrollAmount = p->pagesize; - if (scrollAmount == 0) // no mouse wheel scrolling (or t->pagesize == 0) - return; - // the rest of this is basically http://blogs.msdn.com/b/oldnewthing/archive/2003/08/07/54615.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/08/11/54624.aspx - // see those pages for information on subtleties - delta += *(p->wheelCarry); - lines = delta * ((int) scrollAmount) / WHEEL_DELTA; - *(p->wheelCarry) = delta - lines * WHEEL_DELTA / ((int) scrollAmount); - scrollby(a, which, p, -lines); -} - -static void hscrollParams(uiArea *a, struct scrollParams *p) -{ - RECT r; - - ZeroMemory(p, sizeof (struct scrollParams)); - p->pos = &(a->hscrollpos); - // TODO get rid of these and replace with points - uiWindowsEnsureGetClientRect(a->hwnd, &r); - p->pagesize = r.right - r.left; - p->length = a->scrollWidth; - p->wheelCarry = &(a->hwheelCarry); - p->wheelSPIAction = SPI_GETWHEELSCROLLCHARS; -} - -static void hscrollto(uiArea *a, int pos) -{ - struct scrollParams p; - - hscrollParams(a, &p); - scrollto(a, SB_HORZ, &p, pos); -} - -static void hscrollby(uiArea *a, int delta) -{ - struct scrollParams p; - - hscrollParams(a, &p); - scrollby(a, SB_HORZ, &p, delta); -} - -static void hscroll(uiArea *a, WPARAM wParam, LPARAM lParam) -{ - struct scrollParams p; - - hscrollParams(a, &p); - scroll(a, SB_HORZ, &p, wParam, lParam); -} - -static void hwheelscroll(uiArea *a, WPARAM wParam, LPARAM lParam) -{ - struct scrollParams p; - - hscrollParams(a, &p); - wheelscroll(a, SB_HORZ, &p, wParam, lParam); -} - -static void vscrollParams(uiArea *a, struct scrollParams *p) -{ - RECT r; - - ZeroMemory(p, sizeof (struct scrollParams)); - p->pos = &(a->vscrollpos); - uiWindowsEnsureGetClientRect(a->hwnd, &r); - p->pagesize = r.bottom - r.top; - p->length = a->scrollHeight; - p->wheelCarry = &(a->vwheelCarry); - p->wheelSPIAction = SPI_GETWHEELSCROLLLINES; -} - -static void vscrollto(uiArea *a, int pos) -{ - struct scrollParams p; - - vscrollParams(a, &p); - scrollto(a, SB_VERT, &p, pos); -} - -static void vscrollby(uiArea *a, int delta) -{ - struct scrollParams p; - - vscrollParams(a, &p); - scrollby(a, SB_VERT, &p, delta); -} - -static void vscroll(uiArea *a, WPARAM wParam, LPARAM lParam) -{ - struct scrollParams p; - - vscrollParams(a, &p); - scroll(a, SB_VERT, &p, wParam, lParam); -} - -static void vwheelscroll(uiArea *a, WPARAM wParam, LPARAM lParam) -{ - struct scrollParams p; - - vscrollParams(a, &p); - wheelscroll(a, SB_VERT, &p, wParam, lParam); -} - -BOOL areaDoScroll(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult) -{ - switch (uMsg) { - case WM_HSCROLL: - hscroll(a, wParam, lParam); - *lResult = 0; - return TRUE; - case WM_MOUSEHWHEEL: - hwheelscroll(a, wParam, lParam); - *lResult = 0; - return TRUE; - case WM_VSCROLL: - vscroll(a, wParam, lParam); - *lResult = 0; - return TRUE; - case WM_MOUSEWHEEL: - vwheelscroll(a, wParam, lParam); - *lResult = 0; - return TRUE; - } - return FALSE; -} - -void areaScrollOnResize(uiArea *a, RECT *client) -{ - areaUpdateScroll(a); -} - -void areaUpdateScroll(uiArea *a) -{ - // use a no-op scroll to simulate scrolling - hscrollby(a, 0); - vscrollby(a, 0); -} diff --git a/deps/libui/windows/areautil.cpp b/deps/libui/windows/areautil.cpp deleted file mode 100644 index 9dc72fbb4a..0000000000 --- a/deps/libui/windows/areautil.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// 18 december 2015 -#include "uipriv_windows.hpp" -#include "area.hpp" - -void loadAreaSize(uiArea *a, ID2D1RenderTarget *rt, double *width, double *height) -{ - D2D1_SIZE_F size; - - *width = 0; - *height = 0; - if (!a->scrolling) { - if (rt == NULL) - rt = a->rt; - size = realGetSize(rt); - *width = size.width; - *height = size.height; - } -} - -void pixelsToDIP(uiArea *a, double *x, double *y) -{ - FLOAT dpix, dpiy; - - a->rt->GetDpi(&dpix, &dpiy); - // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd756649%28v=vs.85%29.aspx (and others; search "direct2d mouse") - *x = (*x * 96) / dpix; - *y = (*y * 96) / dpiy; -} - -void dipToPixels(uiArea *a, double *x, double *y) -{ - FLOAT dpix, dpiy; - - a->rt->GetDpi(&dpix, &dpiy); - *x = (*x * dpix) / 96; - *y = (*y * dpiy) / 96; -} diff --git a/deps/libui/windows/box.cpp b/deps/libui/windows/box.cpp deleted file mode 100644 index 9567954b5c..0000000000 --- a/deps/libui/windows/box.cpp +++ /dev/null @@ -1,320 +0,0 @@ -// 7 april 2015 -#include "uipriv_windows.hpp" - -struct boxChild { - uiControl *c; - int stretchy; - int width; - int height; -}; - -struct uiBox { - uiWindowsControl c; - HWND hwnd; - std::vector *controls; - int vertical; - int padded; -}; - -static void boxPadding(uiBox *b, int *xpadding, int *ypadding) -{ - uiWindowsSizing sizing; - - *xpadding = 0; - *ypadding = 0; - if (b->padded) { - uiWindowsGetSizing(b->hwnd, &sizing); - uiWindowsSizingStandardPadding(&sizing, xpadding, ypadding); - } -} - -static void boxRelayout(uiBox *b) -{ - RECT r; - int x, y, width, height; - int xpadding, ypadding; - int nStretchy; - int stretchywid, stretchyht; - int i; - int minimumWidth, minimumHeight; - int nVisible; - uiWindowsSizing *d; - - if (b->controls->size() == 0) - return; - - uiWindowsEnsureGetClientRect(b->hwnd, &r); - x = r.left; - y = r.top; - width = r.right - r.left; - height = r.bottom - r.top; - - // -1) get this Box's padding - boxPadding(b, &xpadding, &ypadding); - - // 1) get width and height of non-stretchy controls - // this will tell us how much space will be left for stretchy controls - stretchywid = width; - stretchyht = height; - nStretchy = 0; - nVisible = 0; - for (struct boxChild &bc : *(b->controls)) { - if (!uiControlVisible(bc.c)) - continue; - nVisible++; - if (bc.stretchy) { - nStretchy++; - continue; - } - uiWindowsControlMinimumSize(uiWindowsControl(bc.c), &minimumWidth, &minimumHeight); - if (b->vertical) { // all controls have same width - bc.width = width; - bc.height = minimumHeight; - stretchyht -= minimumHeight; - } else { // all controls have same height - bc.width = minimumWidth; - bc.height = height; - stretchywid -= minimumWidth; - } - } - if (nVisible == 0) // nothing to do - return; - - // 2) now inset the available rect by the needed padding - if (b->vertical) { - height -= (nVisible - 1) * ypadding; - stretchyht -= (nVisible - 1) * ypadding; - } else { - width -= (nVisible - 1) * xpadding; - stretchywid -= (nVisible - 1) * xpadding; - } - - // 3) now get the size of stretchy controls - if (nStretchy != 0) { - if (b->vertical) - stretchyht /= nStretchy; - else - stretchywid /= nStretchy; - for (struct boxChild &bc : *(b->controls)) { - if (!uiControlVisible(bc.c)) - continue; - if (bc.stretchy) { - bc.width = stretchywid; - bc.height = stretchyht; - } - } - } - - // 4) now we can position controls - // first, make relative to the top-left corner of the container - x = 0; - y = 0; - for (const struct boxChild &bc : *(b->controls)) { - if (!uiControlVisible(bc.c)) - continue; - uiWindowsEnsureMoveWindowDuringResize((HWND) uiControlHandle(bc.c), x, y, bc.width, bc.height); - if (b->vertical) - y += bc.height + ypadding; - else - x += bc.width + xpadding; - } -} - -static void uiBoxDestroy(uiControl *c) -{ - uiBox *b = uiBox(c); - - for (const struct boxChild &bc : *(b->controls)) { - uiControlSetParent(bc.c, NULL); - uiControlDestroy(bc.c); - } - delete b->controls; - uiWindowsEnsureDestroyWindow(b->hwnd); - uiFreeControl(uiControl(b)); -} - -uiWindowsControlDefaultHandle(uiBox) -uiWindowsControlDefaultParent(uiBox) -uiWindowsControlDefaultSetParent(uiBox) -uiWindowsControlDefaultToplevel(uiBox) -uiWindowsControlDefaultVisible(uiBox) -uiWindowsControlDefaultShow(uiBox) -uiWindowsControlDefaultHide(uiBox) -uiWindowsControlDefaultEnabled(uiBox) -uiWindowsControlDefaultEnable(uiBox) -uiWindowsControlDefaultDisable(uiBox) - -static void uiBoxSyncEnableState(uiWindowsControl *c, int enabled) -{ - uiBox *b = uiBox(c); - - if (uiWindowsShouldStopSyncEnableState(uiWindowsControl(b), enabled)) - return; - for (const struct boxChild &bc : *(b->controls)) - uiWindowsControlSyncEnableState(uiWindowsControl(bc.c), enabled); -} - -uiWindowsControlDefaultSetParentHWND(uiBox) - -static void uiBoxMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiBox *b = uiBox(c); - int xpadding, ypadding; - int nStretchy; - // these two contain the largest minimum width and height of all stretchy controls in the box - // all stretchy controls will use this value to determine the final minimum size - int maxStretchyWidth, maxStretchyHeight; - int i; - int minimumWidth, minimumHeight; - int nVisible; - uiWindowsSizing sizing; - - *width = 0; - *height = 0; - if (b->controls->size() == 0) - return; - - // 0) get this Box's padding - boxPadding(b, &xpadding, &ypadding); - - // 1) add in the size of non-stretchy controls and get (but not add in) the largest widths and heights of stretchy controls - // we still add in like direction of stretchy controls - nStretchy = 0; - maxStretchyWidth = 0; - maxStretchyHeight = 0; - nVisible = 0; - for (const struct boxChild &bc : *(b->controls)) { - if (!uiControlVisible(bc.c)) - continue; - nVisible++; - uiWindowsControlMinimumSize(uiWindowsControl(bc.c), &minimumWidth, &minimumHeight); - if (bc.stretchy) { - nStretchy++; - if (maxStretchyWidth < minimumWidth) - maxStretchyWidth = minimumWidth; - if (maxStretchyHeight < minimumHeight) - maxStretchyHeight = minimumHeight; - } - if (b->vertical) { - if (*width < minimumWidth) - *width = minimumWidth; - if (!bc.stretchy) - *height += minimumHeight; - } else { - if (!bc.stretchy) - *width += minimumWidth; - if (*height < minimumHeight) - *height = minimumHeight; - } - } - if (nVisible == 0) // just return 0x0 - return; - - // 2) now outset the desired rect with the needed padding - if (b->vertical) - *height += (nVisible - 1) * ypadding; - else - *width += (nVisible - 1) * xpadding; - - // 3) and now we can add in stretchy controls - if (b->vertical) - *height += nStretchy * maxStretchyHeight; - else - *width += nStretchy * maxStretchyWidth; -} - -static void uiBoxMinimumSizeChanged(uiWindowsControl *c) -{ - uiBox *b = uiBox(c); - - if (uiWindowsControlTooSmall(uiWindowsControl(b))) { - uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(b)); - return; - } - boxRelayout(b); -} - -uiWindowsControlDefaultLayoutRect(uiBox) -uiWindowsControlDefaultAssignControlIDZOrder(uiBox) - -static void uiBoxChildVisibilityChanged(uiWindowsControl *c) -{ - // TODO eliminate the redundancy - uiWindowsControlMinimumSizeChanged(c); -} - -static void boxArrangeChildren(uiBox *b) -{ - LONG_PTR controlID; - HWND insertAfter; - - controlID = 100; - insertAfter = NULL; - for (const struct boxChild &bc : *(b->controls)) - uiWindowsControlAssignControlIDZOrder(uiWindowsControl(bc.c), &controlID, &insertAfter); -} - -void uiBoxAppend(uiBox *b, uiControl *c, int stretchy) -{ - struct boxChild bc; - - bc.c = c; - bc.stretchy = stretchy; - uiControlSetParent(bc.c, uiControl(b)); - uiWindowsControlSetParentHWND(uiWindowsControl(bc.c), b->hwnd); - b->controls->push_back(bc); - boxArrangeChildren(b); - uiWindowsControlMinimumSizeChanged(uiWindowsControl(b)); -} - -void uiBoxDelete(uiBox *b, int index) -{ - uiControl *c; - - c = (*(b->controls))[index].c; - uiControlSetParent(c, NULL); - uiWindowsControlSetParentHWND(uiWindowsControl(c), NULL); - b->controls->erase(b->controls->begin() + index); - boxArrangeChildren(b); - uiWindowsControlMinimumSizeChanged(uiWindowsControl(b)); -} - -int uiBoxPadded(uiBox *b) -{ - return b->padded; -} - -void uiBoxSetPadded(uiBox *b, int padded) -{ - b->padded = padded; - uiWindowsControlMinimumSizeChanged(uiWindowsControl(b)); -} - -static void onResize(uiWindowsControl *c) -{ - boxRelayout(uiBox(c)); -} - -static uiBox *finishNewBox(int vertical) -{ - uiBox *b; - - uiWindowsNewControl(uiBox, b); - - b->hwnd = uiWindowsMakeContainer(uiWindowsControl(b), onResize); - - b->vertical = vertical; - b->controls = new std::vector; - - return b; -} - -uiBox *uiNewHorizontalBox(void) -{ - return finishNewBox(0); -} - -uiBox *uiNewVerticalBox(void) -{ - return finishNewBox(1); -} diff --git a/deps/libui/windows/button.cpp b/deps/libui/windows/button.cpp deleted file mode 100644 index 3b12e726db..0000000000 --- a/deps/libui/windows/button.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// 7 april 2015 -#include "uipriv_windows.hpp" - -struct uiButton { - uiWindowsControl c; - HWND hwnd; - void (*onClicked)(uiButton *, void *); - void *onClickedData; -}; - -static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult) -{ - uiButton *b = uiButton(c); - - if (code != BN_CLICKED) - return FALSE; - (*(b->onClicked))(b, b->onClickedData); - *lResult = 0; - return TRUE; -} - -static void uiButtonDestroy(uiControl *c) -{ - uiButton *b = uiButton(c); - - uiWindowsUnregisterWM_COMMANDHandler(b->hwnd); - uiWindowsEnsureDestroyWindow(b->hwnd); - uiFreeControl(uiControl(b)); -} - -uiWindowsControlAllDefaultsExceptDestroy(uiButton) - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define buttonHeight 14 - -static void uiButtonMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiButton *b = uiButton(c); - SIZE size; - uiWindowsSizing sizing; - int y; - - // try the comctl32 version 6 way - size.cx = 0; // explicitly ask for ideal size - size.cy = 0; - if (SendMessageW(b->hwnd, BCM_GETIDEALSIZE, 0, (LPARAM) (&size)) != FALSE) { - *width = size.cx; - *height = size.cy; - return; - } - - // that didn't work; fall back to using Microsoft's metrics - // Microsoft says to use a fixed width for all buttons; this isn't good enough - // use the text width instead, with some edge padding - *width = uiWindowsWindowTextWidth(b->hwnd) + (2 * GetSystemMetrics(SM_CXEDGE)); - y = buttonHeight; - uiWindowsGetSizing(b->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &y); - *height = y; -} - -static void defaultOnClicked(uiButton *b, void *data) -{ - // do nothing -} - -char *uiButtonText(uiButton *b) -{ - return uiWindowsWindowText(b->hwnd); -} - -void uiButtonSetText(uiButton *b, const char *text) -{ - uiWindowsSetWindowText(b->hwnd, text); - // changing the text might necessitate a change in the button's size - uiWindowsControlMinimumSizeChanged(uiWindowsControl(b)); -} - -void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *, void *), void *data) -{ - b->onClicked = f; - b->onClickedData = data; -} - -uiButton *uiNewButton(const char *text) -{ - uiButton *b; - WCHAR *wtext; - - uiWindowsNewControl(uiButton, b); - - wtext = toUTF16(text); - b->hwnd = uiWindowsEnsureCreateControlHWND(0, - L"button", wtext, - BS_PUSHBUTTON | WS_TABSTOP, - hInstance, NULL, - TRUE); - uiFree(wtext); - - uiWindowsRegisterWM_COMMANDHandler(b->hwnd, onWM_COMMAND, uiControl(b)); - uiButtonOnClicked(b, defaultOnClicked, NULL); - - return b; -} diff --git a/deps/libui/windows/checkbox.cpp b/deps/libui/windows/checkbox.cpp deleted file mode 100644 index be425c0041..0000000000 --- a/deps/libui/windows/checkbox.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// 7 april 2015 -#include "uipriv_windows.hpp" - -struct uiCheckbox { - uiWindowsControl c; - HWND hwnd; - void (*onToggled)(uiCheckbox *, void *); - void *onToggledData; -}; - -static BOOL onWM_COMMAND(uiControl *cc, HWND hwnd, WORD code, LRESULT *lResult) -{ - uiCheckbox *c = uiCheckbox(cc); - WPARAM check; - - if (code != BN_CLICKED) - return FALSE; - - // we didn't use BS_AUTOCHECKBOX (http://blogs.msdn.com/b/oldnewthing/archive/2014/05/22/10527522.aspx) so we have to manage the check state ourselves - check = BST_CHECKED; - if (SendMessage(c->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) - check = BST_UNCHECKED; - SendMessage(c->hwnd, BM_SETCHECK, check, 0); - - (*(c->onToggled))(c, c->onToggledData); - *lResult = 0; - return TRUE; -} - -static void uiCheckboxDestroy(uiControl *cc) -{ - uiCheckbox *c = uiCheckbox(cc); - - uiWindowsUnregisterWM_COMMANDHandler(c->hwnd); - uiWindowsEnsureDestroyWindow(c->hwnd); - uiFreeControl(uiControl(c)); -} - -uiWindowsControlAllDefaultsExceptDestroy(uiCheckbox) - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define checkboxHeight 10 -// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx -#define checkboxXFromLeftOfBoxToLeftOfLabel 12 - -static void uiCheckboxMinimumSize(uiWindowsControl *cc, int *width, int *height) -{ - uiCheckbox *c = uiCheckbox(cc); - uiWindowsSizing sizing; - int x, y; - - x = checkboxXFromLeftOfBoxToLeftOfLabel; - y = checkboxHeight; - uiWindowsGetSizing(c->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - *width = x + uiWindowsWindowTextWidth(c->hwnd); - *height = y; -} - -static void defaultOnToggled(uiCheckbox *c, void *data) -{ - // do nothing -} - -char *uiCheckboxText(uiCheckbox *c) -{ - return uiWindowsWindowText(c->hwnd); -} - -void uiCheckboxSetText(uiCheckbox *c, const char *text) -{ - uiWindowsSetWindowText(c->hwnd, text); - // changing the text might necessitate a change in the checkbox's size - uiWindowsControlMinimumSizeChanged(uiWindowsControl(c)); -} - -void uiCheckboxOnToggled(uiCheckbox *c, void (*f)(uiCheckbox *, void *), void *data) -{ - c->onToggled = f; - c->onToggledData = data; -} - -int uiCheckboxChecked(uiCheckbox *c) -{ - return SendMessage(c->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED; -} - -void uiCheckboxSetChecked(uiCheckbox *c, int checked) -{ - WPARAM check; - - check = BST_CHECKED; - if (!checked) - check = BST_UNCHECKED; - SendMessage(c->hwnd, BM_SETCHECK, check, 0); -} - -uiCheckbox *uiNewCheckbox(const char *text) -{ - uiCheckbox *c; - WCHAR *wtext; - - uiWindowsNewControl(uiCheckbox, c); - - wtext = toUTF16(text); - c->hwnd = uiWindowsEnsureCreateControlHWND(0, - L"button", wtext, - BS_CHECKBOX | WS_TABSTOP, - hInstance, NULL, - TRUE); - uiFree(wtext); - - uiWindowsRegisterWM_COMMANDHandler(c->hwnd, onWM_COMMAND, uiControl(c)); - uiCheckboxOnToggled(c, defaultOnToggled, NULL); - - return c; -} diff --git a/deps/libui/windows/colorbutton.cpp b/deps/libui/windows/colorbutton.cpp deleted file mode 100644 index c1ba6954ec..0000000000 --- a/deps/libui/windows/colorbutton.cpp +++ /dev/null @@ -1,192 +0,0 @@ -// 16 may 2016 -#include "uipriv_windows.hpp" - -struct uiColorButton { - uiWindowsControl c; - HWND hwnd; - double r; - double g; - double b; - double a; - void (*onChanged)(uiColorButton *, void *); - void *onChangedData; -}; - -static void uiColorButtonDestroy(uiControl *c) -{ - uiColorButton *b = uiColorButton(c); - - uiWindowsUnregisterWM_COMMANDHandler(b->hwnd); - uiWindowsUnregisterWM_NOTIFYHandler(b->hwnd); - uiWindowsEnsureDestroyWindow(b->hwnd); - uiFreeControl(uiControl(b)); -} - -static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult) -{ - uiColorButton *b = uiColorButton(c); - HWND parent; - struct colorDialogRGBA rgba; - - if (code != BN_CLICKED) - return FALSE; - - parent = parentToplevel(b->hwnd); - rgba.r = b->r; - rgba.g = b->g; - rgba.b = b->b; - rgba.a = b->a; - if (showColorDialog(parent, &rgba)) { - b->r = rgba.r; - b->g = rgba.g; - b->b = rgba.b; - b->a = rgba.a; - invalidateRect(b->hwnd, NULL, TRUE); - (*(b->onChanged))(b, b->onChangedData); - } - - *lResult = 0; - return TRUE; -} - -static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult) -{ - uiColorButton *b = uiColorButton(c); - NMCUSTOMDRAW *nm = (NMCUSTOMDRAW *) nmhdr; - RECT client; - ID2D1DCRenderTarget *rt; - D2D1_RECT_F r; - D2D1_COLOR_F color; - D2D1_BRUSH_PROPERTIES bprop; - ID2D1SolidColorBrush *brush; - uiWindowsSizing sizing; - int x, y; - HRESULT hr; - - if (nmhdr->code != NM_CUSTOMDRAW) - return FALSE; - // and allow the button to draw its background - if (nm->dwDrawStage != CDDS_PREPAINT) - return FALSE; - - uiWindowsEnsureGetClientRect(b->hwnd, &client); - rt = makeHDCRenderTarget(nm->hdc, &client); - rt->BeginDraw(); - - uiWindowsGetSizing(b->hwnd, &sizing); - x = 3; // should be enough - y = 3; - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - r.left = client.left + x; - r.top = client.top + y; - r.right = client.right - x; - r.bottom = client.bottom - y; - - color.r = b->r; - color.g = b->g; - color.b = b->b; - color.a = b->a; - ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); - bprop.opacity = 1.0; - bprop.transform._11 = 1; - bprop.transform._22 = 1; - hr = rt->CreateSolidColorBrush(&color, &bprop, &brush); - if (hr != S_OK) - logHRESULT(L"error creating brush for color button", hr); - rt->FillRectangle(&r, brush); - brush->Release(); - - hr = rt->EndDraw(NULL, NULL); - if (hr != S_OK) - logHRESULT(L"error drawing color on color button", hr); - rt->Release(); - - // skip default processing (don't draw text) - *lResult = CDRF_SKIPDEFAULT; - return TRUE; -} - -uiWindowsControlAllDefaultsExceptDestroy(uiColorButton) - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define buttonHeight 14 - -// TODO check widths -static void uiColorButtonMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiColorButton *b = uiColorButton(c); - SIZE size; - uiWindowsSizing sizing; - int y; - - // try the comctl32 version 6 way - size.cx = 0; // explicitly ask for ideal size - size.cy = 0; - if (SendMessageW(b->hwnd, BCM_GETIDEALSIZE, 0, (LPARAM) (&size)) != FALSE) { - *width = size.cx; - *height = size.cy; - return; - } - - // that didn't work; fall back to using Microsoft's metrics - // Microsoft says to use a fixed width for all buttons; this isn't good enough - // use the text width instead, with some edge padding - *width = uiWindowsWindowTextWidth(b->hwnd) + (2 * GetSystemMetrics(SM_CXEDGE)); - y = buttonHeight; - uiWindowsGetSizing(b->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &y); - *height = y; -} - -static void defaultOnChanged(uiColorButton *b, void *data) -{ - // do nothing -} - -void uiColorButtonColor(uiColorButton *b, double *r, double *g, double *bl, double *a) -{ - *r = b->r; - *g = b->g; - *bl = b->b; - *a = b->a; -} - -void uiColorButtonSetColor(uiColorButton *b, double r, double g, double bl, double a) -{ - b->r = r; - b->g = g; - b->b = bl; - b->a = a; - invalidateRect(b->hwnd, NULL, TRUE); -} - -void uiColorButtonOnChanged(uiColorButton *b, void (*f)(uiColorButton *, void *), void *data) -{ - b->onChanged = f; - b->onChangedData = data; -} - -uiColorButton *uiNewColorButton(void) -{ - uiColorButton *b; - - uiWindowsNewControl(uiColorButton, b); - - // initial color is black - b->r = 0.0; - b->g = 0.0; - b->b = 0.0; - b->a = 1.0; - - b->hwnd = uiWindowsEnsureCreateControlHWND(0, - L"button", L" ", // TODO; can't use "" TODO - BS_PUSHBUTTON | WS_TABSTOP, - hInstance, NULL, - TRUE); - - uiWindowsRegisterWM_COMMANDHandler(b->hwnd, onWM_COMMAND, uiControl(b)); - uiWindowsRegisterWM_NOTIFYHandler(b->hwnd, onWM_NOTIFY, uiControl(b)); - uiColorButtonOnChanged(b, defaultOnChanged, NULL); - - return b; -} diff --git a/deps/libui/windows/colordialog.cpp b/deps/libui/windows/colordialog.cpp deleted file mode 100644 index 2efe72c8c8..0000000000 --- a/deps/libui/windows/colordialog.cpp +++ /dev/null @@ -1,1264 +0,0 @@ -// 16 may 2016 -#include "uipriv_windows.hpp" - -// TODO should the d2dscratch programs capture mouse? - -struct colorDialog { - HWND hwnd; - - HWND svChooser; - HWND hSlider; - HWND preview; - HWND opacitySlider; - HWND editH; - HWND editS; - HWND editV; - HWND editRDouble, editRInt; - HWND editGDouble, editGInt; - HWND editBDouble, editBInt; - HWND editADouble, editAInt; - HWND editHex; - - double h; - double s; - double v; - double a; - struct colorDialogRGBA *out; - - BOOL updating; -}; - -// both of these are from the wikipedia page on HSV -// TODO what to do about negative h? -static void rgb2HSV(double r, double g, double b, double *h, double *s, double *v) -{ - double M, m; - int whichmax; - double c; - - M = r; - whichmax = 0; - if (M < g) { - M = g; - whichmax = 1; - } - if (M < b) { - M = b; - whichmax = 2; - } - m = r; - if (m > g) - m = g; - if (m > b) - m = b; - c = M - m; - - if (c == 0) - *h = 0; - else { - switch (whichmax) { - case 0: - *h = ((g - b) / c); - *h = fmod(*h, 6); - break; - case 1: - *h = ((b - r) / c) + 2; - break; - case 2: - *h = ((r - g) / c) + 4; - break; - } - *h /= 6; // put in range [0,1) - } - - *v = M; - - if (c == 0) - *s = 0; - else - *s = c / *v; -} - -// TODO negative R values? -static void hsv2RGB(double h, double s, double v, double *r, double *g, double *b) -{ - double c; - double hPrime; - int h60; - double x; - double m; - double c1, c2; - - c = v * s; - hPrime = h * 6; - h60 = (int) hPrime; // equivalent to splitting into 60° chunks - x = c * (1.0 - fabs(fmod(hPrime, 2) - 1.0)); - m = v - c; - switch (h60) { - case 0: - *r = c + m; - *g = x + m; - *b = m; - return; - case 1: - *r = x + m; - *g = c + m; - *b = m; - return; - case 2: - *r = m; - *g = c + m; - *b = x + m; - return; - case 3: - *r = m; - *g = x + m; - *b = c + m; - return; - case 4: - *r = x + m; - *g = m; - *b = c + m; - return; - case 5: - *r = c + m; - *g = m; - *b = x + m; - return; - } - // TODO -} - -#define hexd L"0123456789ABCDEF" - -static void rgba2Hex(uint8_t r, uint8_t g, uint8_t b, uint8_t a, WCHAR *buf) -{ - buf[0] = L'#'; - buf[1] = hexd[(a >> 4) & 0xF]; - buf[2] = hexd[a & 0xF]; - buf[3] = hexd[(r >> 4) & 0xF]; - buf[4] = hexd[r & 0xF]; - buf[5] = hexd[(g >> 4) & 0xF]; - buf[6] = hexd[g & 0xF]; - buf[7] = hexd[(b >> 4) & 0xF]; - buf[8] = hexd[b & 0xF]; - buf[9] = L'\0'; -} - -static int convHexDigit(WCHAR c) -{ - if (c >= L'0' && c <= L'9') - return c - L'0'; - if (c >= L'A' && c <= L'F') - return c - L'A' + 0xA; - if (c >= L'a' && c <= L'f') - return c - L'a' + 0xA; - return -1; -} - -// TODO allow #NNN shorthand -static BOOL hex2RGBA(WCHAR *buf, double *r, double *g, double *b, double *a) -{ - uint8_t component; - int i; - - if (*buf == L'#') - buf++; - - component = 0; - i = convHexDigit(*buf++); - if (i < 0) - return FALSE; - component |= ((uint8_t) i) << 4; - i = convHexDigit(*buf++); - if (i < 0) - return FALSE; - component |= ((uint8_t) i); - *a = ((double) component) / 255; - - component = 0; - i = convHexDigit(*buf++); - if (i < 0) - return FALSE; - component |= ((uint8_t) i) << 4; - i = convHexDigit(*buf++); - if (i < 0) - return FALSE; - component |= ((uint8_t) i); - *r = ((double) component) / 255; - - component = 0; - i = convHexDigit(*buf++); - if (i < 0) - return FALSE; - component |= ((uint8_t) i) << 4; - i = convHexDigit(*buf++); - if (i < 0) - return FALSE; - component |= ((uint8_t) i); - *g = ((double) component) / 255; - - if (*buf == L'\0') { // #NNNNNN syntax - *b = *g; - *g = *r; - *r = *a; - *a = 1; - return TRUE; - } - - component = 0; - i = convHexDigit(*buf++); - if (i < 0) - return FALSE; - component |= ((uint8_t) i) << 4; - i = convHexDigit(*buf++); - if (i < 0) - return FALSE; - component |= ((uint8_t) i); - *b = ((double) component) / 255; - - return *buf == L'\0'; -} - -static void updateDouble(HWND hwnd, double d, HWND whichChanged) -{ - WCHAR *str; - - if (whichChanged == hwnd) - return; - str = ftoutf16(d); - setWindowText(hwnd, str); - uiFree(str); -} - -static void updateDialog(struct colorDialog *c, HWND whichChanged) -{ - double r, g, b; - uint8_t rb, gb, bb, ab; - WCHAR *str; - WCHAR hexbuf[16]; // more than enough - - c->updating = TRUE; - - updateDouble(c->editH, c->h, whichChanged); - updateDouble(c->editS, c->s, whichChanged); - updateDouble(c->editV, c->v, whichChanged); - - hsv2RGB(c->h, c->s, c->v, &r, &g, &b); - - updateDouble(c->editRDouble, r, whichChanged); - updateDouble(c->editGDouble, g, whichChanged); - updateDouble(c->editBDouble, b, whichChanged); - updateDouble(c->editADouble, c->a, whichChanged); - - rb = (uint8_t) (r * 255); - gb = (uint8_t) (g * 255); - bb = (uint8_t) (b * 255); - ab = (uint8_t) (c->a * 255); - - if (whichChanged != c->editRInt) { - str = itoutf16(rb); - setWindowText(c->editRInt, str); - uiFree(str); - } - if (whichChanged != c->editGInt) { - str = itoutf16(gb); - setWindowText(c->editGInt, str); - uiFree(str); - } - if (whichChanged != c->editBInt) { - str = itoutf16(bb); - setWindowText(c->editBInt, str); - uiFree(str); - } - if (whichChanged != c->editAInt) { - str = itoutf16(ab); - setWindowText(c->editAInt, str); - uiFree(str); - } - - if (whichChanged != c->editHex) { - rgba2Hex(rb, gb, bb, ab, hexbuf); - setWindowText(c->editHex, hexbuf); - } - - // TODO TRUE? - invalidateRect(c->svChooser, NULL, TRUE); - invalidateRect(c->hSlider, NULL, TRUE); - invalidateRect(c->preview, NULL, TRUE); - invalidateRect(c->opacitySlider, NULL, TRUE); - - c->updating = FALSE; -} - -// this imitates http://blogs.msdn.com/b/wpfsdk/archive/2006/10/26/uncommon-dialogs--font-chooser-and-color-picker-dialogs.aspx -static void drawGrid(ID2D1RenderTarget *rt, D2D1_RECT_F *fillRect) -{ - D2D1_SIZE_F size; - D2D1_PIXEL_FORMAT pformat; - ID2D1BitmapRenderTarget *brt; - D2D1_COLOR_F color; - D2D1_BRUSH_PROPERTIES bprop; - ID2D1SolidColorBrush *brush; - D2D1_RECT_F rect; - ID2D1Bitmap *bitmap; - D2D1_BITMAP_BRUSH_PROPERTIES bbp; - ID2D1BitmapBrush *bb; - HRESULT hr; - - // mind the divisions; they represent the fact the original uses a viewport - size.width = 100 / 10; - size.height = 100 / 10; - // yay more ABI bugs -#ifdef _MSC_VER - pformat = rt->GetPixelFormat(); -#else - { - typedef D2D1_PIXEL_FORMAT *(__stdcall ID2D1RenderTarget::* GetPixelFormatF)(D2D1_PIXEL_FORMAT *); - GetPixelFormatF gpf; - - gpf = (GetPixelFormatF) (&(rt->GetPixelFormat)); - (rt->*gpf)(&pformat); - } -#endif - hr = rt->CreateCompatibleRenderTarget(&size, NULL, - &pformat, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, - &brt); - if (hr != S_OK) - logHRESULT(L"error creating render target for grid", hr); - - brt->BeginDraw(); - - color.r = 1.0; - color.g = 1.0; - color.b = 1.0; - color.a = 1.0; - brt->Clear(&color); - - color = D2D1::ColorF(D2D1::ColorF::LightGray, 1.0); - ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); - bprop.opacity = 1.0; - bprop.transform._11 = 1; - bprop.transform._22 = 1; - hr = brt->CreateSolidColorBrush(&color, &bprop, &brush); - if (hr != S_OK) - logHRESULT(L"error creating brush for grid", hr); - rect.left = 0; - rect.top = 0; - rect.right = 50 / 10; - rect.bottom = 50 / 10; - brt->FillRectangle(&rect, brush); - rect.left = 50 / 10; - rect.top = 50 / 10; - rect.right = 100 / 10; - rect.bottom = 100 / 10; - brt->FillRectangle(&rect, brush); - brush->Release(); - - hr = brt->EndDraw(NULL, NULL); - if (hr != S_OK) - logHRESULT(L"error finalizing render target for grid", hr); - hr = brt->GetBitmap(&bitmap); - if (hr != S_OK) - logHRESULT(L"error getting bitmap for grid", hr); - brt->Release(); - - ZeroMemory(&bbp, sizeof (D2D1_BITMAP_BRUSH_PROPERTIES)); - bbp.extendModeX = D2D1_EXTEND_MODE_WRAP; - bbp.extendModeY = D2D1_EXTEND_MODE_WRAP; - bbp.interpolationMode = D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR; - hr = rt->CreateBitmapBrush(bitmap, &bbp, &bprop, &bb); - if (hr != S_OK) - logHRESULT(L"error creating bitmap brush for grid", hr); - rt->FillRectangle(fillRect, bb); - bb->Release(); - bitmap->Release(); -} - -// this interesting approach comes from http://blogs.msdn.com/b/wpfsdk/archive/2006/10/26/uncommon-dialogs--font-chooser-and-color-picker-dialogs.aspx -static void drawSVChooser(struct colorDialog *c, ID2D1RenderTarget *rt) -{ - D2D1_SIZE_F size; - D2D1_RECT_F rect; - double rTop, gTop, bTop; - D2D1_GRADIENT_STOP stops[2]; - ID2D1GradientStopCollection *collection; - D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lprop; - D2D1_BRUSH_PROPERTIES bprop; - ID2D1LinearGradientBrush *brush; - ID2D1LinearGradientBrush *opacity; - ID2D1Layer *layer; - D2D1_LAYER_PARAMETERS layerparams; - D2D1_ELLIPSE mparam; - D2D1_COLOR_F mcolor; - ID2D1SolidColorBrush *markerBrush; - HRESULT hr; - - size = realGetSize(rt); - rect.left = 0; - rect.top = 0; - rect.right = size.width; - rect.bottom = size.height; - - drawGrid(rt, &rect); - - // first, draw a vertical gradient from the current hue at max S/V to black - // the source example draws it upside down; let's do so too just to be safe - hsv2RGB(c->h, 1.0, 1.0, &rTop, &gTop, &bTop); - stops[0].position = 0; - stops[0].color.r = 0.0; - stops[0].color.g = 0.0; - stops[0].color.b = 0.0; - stops[0].color.a = 1.0; - stops[1].position = 1; - stops[1].color.r = rTop; - stops[1].color.g = gTop; - stops[1].color.b = bTop; - stops[1].color.a = 1.0; - hr = rt->CreateGradientStopCollection(stops, 2, - D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, - &collection); - if (hr != S_OK) - logHRESULT(L"error making gradient stop collection for first gradient in SV chooser", hr); - ZeroMemory(&lprop, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); - lprop.startPoint.x = size.width / 2; - lprop.startPoint.y = size.height; - lprop.endPoint.x = size.width / 2; - lprop.endPoint.y = 0; - // TODO decide what to do about the duplication of this - ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); - bprop.opacity = c->a; // note this part; we also use it below for the layer - bprop.transform._11 = 1; - bprop.transform._22 = 1; - hr = rt->CreateLinearGradientBrush(&lprop, &bprop, - collection, &brush); - if (hr != S_OK) - logHRESULT(L"error making gradient brush for first gradient in SV chooser", hr); - rt->FillRectangle(&rect, brush); - brush->Release(); - collection->Release(); - - // second, create an opacity mask for the third step: a horizontal gradientthat goes from opaque to translucent - stops[0].position = 0; - stops[0].color.r = 0.0; - stops[0].color.g = 0.0; - stops[0].color.b = 0.0; - stops[0].color.a = 1.0; - stops[1].position = 1; - stops[1].color.r = 0.0; - stops[1].color.g = 0.0; - stops[1].color.b = 0.0; - stops[1].color.a = 0.0; - hr = rt->CreateGradientStopCollection(stops, 2, - D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, - &collection); - if (hr != S_OK) - logHRESULT(L"error making gradient stop collection for opacity mask gradient in SV chooser", hr); - ZeroMemory(&lprop, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); - lprop.startPoint.x = 0; - lprop.startPoint.y = size.height / 2; - lprop.endPoint.x = size.width; - lprop.endPoint.y = size.height / 2; - ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); - bprop.opacity = 1.0; - bprop.transform._11 = 1; - bprop.transform._22 = 1; - hr = rt->CreateLinearGradientBrush(&lprop, &bprop, - collection, &opacity); - if (hr != S_OK) - logHRESULT(L"error making gradient brush for opacity mask gradient in SV chooser", hr); - collection->Release(); - - // finally, make a vertical gradient from white at the top to black at the bottom (right side up this time) and with the previous opacity mask - stops[0].position = 0; - stops[0].color.r = 1.0; - stops[0].color.g = 1.0; - stops[0].color.b = 1.0; - stops[0].color.a = 1.0; - stops[1].position = 1; - stops[1].color.r = 0.0; - stops[1].color.g = 0.0; - stops[1].color.b = 0.0; - stops[1].color.a = 1.0; - hr = rt->CreateGradientStopCollection(stops, 2, - D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, - &collection); - if (hr != S_OK) - logHRESULT(L"error making gradient stop collection for second gradient in SV chooser", hr); - ZeroMemory(&lprop, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); - lprop.startPoint.x = size.width / 2; - lprop.startPoint.y = 0; - lprop.endPoint.x = size.width / 2; - lprop.endPoint.y = size.height; - ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); - bprop.opacity = 1.0; - bprop.transform._11 = 1; - bprop.transform._22 = 1; - hr = rt->CreateLinearGradientBrush(&lprop, &bprop, - collection, &brush); - if (hr != S_OK) - logHRESULT(L"error making gradient brush for second gradient in SV chooser", hr); - // oh but wait we can't use FillRectangle() with an opacity mask - // and we can't use FillGeometry() with both an opacity mask and a non-bitmap - // layers it is! - hr = rt->CreateLayer(&size, &layer); - if (hr != S_OK) - logHRESULT(L"error making layer for second gradient in SV chooser", hr); - ZeroMemory(&layerparams, sizeof (D2D1_LAYER_PARAMETERS)); - layerparams.contentBounds = rect; - // TODO make sure these are right - layerparams.geometricMask = NULL; - layerparams.maskAntialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE; - layerparams.maskTransform._11 = 1; - layerparams.maskTransform._22 = 1; - layerparams.opacity = c->a; // here's the other use of c->a to note - layerparams.opacityBrush = opacity; - layerparams.layerOptions = D2D1_LAYER_OPTIONS_NONE; - rt->PushLayer(&layerparams, layer); - rt->FillRectangle(&rect, brush); - rt->PopLayer(); - layer->Release(); - brush->Release(); - collection->Release(); - opacity->Release(); - - // and now we just draw the marker - ZeroMemory(&mparam, sizeof (D2D1_ELLIPSE)); - mparam.point.x = c->s * size.width; - mparam.point.y = (1 - c->v) * size.height; - mparam.radiusX = 7; - mparam.radiusY = 7; - // TODO make the color contrast? - mcolor.r = 1.0; - mcolor.g = 1.0; - mcolor.b = 1.0; - mcolor.a = 1.0; - bprop.opacity = 1.0; // the marker should always be opaque - hr = rt->CreateSolidColorBrush(&mcolor, &bprop, &markerBrush); - if (hr != S_OK) - logHRESULT(L"error creating brush for SV chooser marker", hr); - rt->DrawEllipse(&mparam, markerBrush, 2, NULL); - markerBrush->Release(); -} - -static LRESULT CALLBACK svChooserSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - ID2D1RenderTarget *rt; - struct colorDialog *c; - D2D1_POINT_2F *pos; - D2D1_SIZE_F *size; - - c = (struct colorDialog *) dwRefData; - switch (uMsg) { - case msgD2DScratchPaint: - rt = (ID2D1RenderTarget *) lParam; - drawSVChooser(c, rt); - return 0; - case msgD2DScratchLButtonDown: - pos = (D2D1_POINT_2F *) wParam; - size = (D2D1_SIZE_F *) lParam; - c->s = pos->x / size->width; - c->v = 1 - (pos->y / size->height); - updateDialog(c, NULL); - return 0; - case WM_NCDESTROY: - if (RemoveWindowSubclass(hwnd, svChooserSubProc, uIdSubclass) == FALSE) - logLastError(L"error removing color dialog SV chooser subclass"); - break; - } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -static void drawArrow(ID2D1RenderTarget *rt, D2D1_POINT_2F center, double hypot) -{ - double leg; - D2D1_RECT_F rect; - D2D1_MATRIX_3X2_F oldtf, rotate; - D2D1_COLOR_F color; - D2D1_BRUSH_PROPERTIES bprop; - ID2D1SolidColorBrush *brush; - HRESULT hr; - - // to avoid needing a geometry, this will just be a rotated square - // compute the length of each side; the diagonal of the square is 2 * offset to gradient - // a^2 + a^2 = c^2 -> 2a^2 = c^2 - // a = sqrt(c^2/2) - hypot *= hypot; - hypot /= 2; - leg = sqrt(hypot); - rect.left = center.x - leg; - rect.top = center.y - leg; - rect.right = center.x + leg; - rect.bottom = center.y + leg; - - // now we need to rotate the render target 45° (either way works) about the center point - rt->GetTransform(&oldtf); - rotate = oldtf * D2D1::Matrix3x2F::Rotation(45, center); - rt->SetTransform(&rotate); - - // and draw - color.r = 0.0; - color.g = 0.0; - color.b = 0.0; - color.a = 1.0; - ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); - bprop.opacity = 1.0; - bprop.transform._11 = 1; - bprop.transform._22 = 1; - hr = rt->CreateSolidColorBrush(&color, &bprop, &brush); - if (hr != S_OK) - logHRESULT(L"error creating brush for arrow", hr); - rt->FillRectangle(&rect, brush); - brush->Release(); - - // clean up - rt->SetTransform(&oldtf); -} - -// the gradient stuff also comes from http://blogs.msdn.com/b/wpfsdk/archive/2006/10/26/uncommon-dialogs--font-chooser-and-color-picker-dialogs.aspx -#define nStops (30) -#define degPerStop (360 / nStops) -#define stopIncr (1.0 / ((double) nStops)) - -static void drawHSlider(struct colorDialog *c, ID2D1RenderTarget *rt) -{ - D2D1_SIZE_F size; - D2D1_RECT_F rect; - D2D1_GRADIENT_STOP stops[nStops]; - double r, g, b; - int i; - double h; - ID2D1GradientStopCollection *collection; - D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lprop; - D2D1_BRUSH_PROPERTIES bprop; - ID2D1LinearGradientBrush *brush; - double hypot; - D2D1_POINT_2F center; - HRESULT hr; - - size = realGetSize(rt); - rect.left = size.width / 6; // leftmost sixth for arrow - rect.top = 0; - rect.right = size.width; - rect.bottom = size.height; - - for (i = 0; i < nStops; i++) { - h = ((double) (i * degPerStop)) / 360.0; - if (i == (nStops - 1)) - h = 0; - hsv2RGB(h, 1.0, 1.0, &r, &g, &b); - stops[i].position = ((double) i) * stopIncr; - stops[i].color.r = r; - stops[i].color.g = g; - stops[i].color.b = b; - stops[i].color.a = 1.0; - } - // and pin the last one - stops[i - 1].position = 1.0; - - hr = rt->CreateGradientStopCollection(stops, nStops, - // note that in this case this gamma is explicitly specified by the original - D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, - &collection); - if (hr != S_OK) - logHRESULT(L"error creating stop collection for H slider gradient", hr); - ZeroMemory(&lprop, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); - lprop.startPoint.x = (rect.right - rect.left) / 2; - lprop.startPoint.y = 0; - lprop.endPoint.x = (rect.right - rect.left) / 2; - lprop.endPoint.y = size.height; - ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); - bprop.opacity = 1.0; - bprop.transform._11 = 1; - bprop.transform._22 = 1; - hr = rt->CreateLinearGradientBrush(&lprop, &bprop, - collection, &brush); - if (hr != S_OK) - logHRESULT(L"error creating gradient brush for H slider", hr); - rt->FillRectangle(&rect, brush); - brush->Release(); - collection->Release(); - - // now draw a black arrow - center.x = 0; - center.y = c->h * size.height; - hypot = rect.left; - drawArrow(rt, center, hypot); -} - -static LRESULT CALLBACK hSliderSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - ID2D1RenderTarget *rt; - struct colorDialog *c; - D2D1_POINT_2F *pos; - D2D1_SIZE_F *size; - - c = (struct colorDialog *) dwRefData; - switch (uMsg) { - case msgD2DScratchPaint: - rt = (ID2D1RenderTarget *) lParam; - drawHSlider(c, rt); - return 0; - case msgD2DScratchLButtonDown: - pos = (D2D1_POINT_2F *) wParam; - size = (D2D1_SIZE_F *) lParam; - c->h = pos->y / size->height; - updateDialog(c, NULL); - return 0; - case WM_NCDESTROY: - if (RemoveWindowSubclass(hwnd, hSliderSubProc, uIdSubclass) == FALSE) - logLastError(L"error removing color dialog H slider subclass"); - break; - } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -static void drawPreview(struct colorDialog *c, ID2D1RenderTarget *rt) -{ - D2D1_SIZE_F size; - D2D1_RECT_F rect; - double r, g, b; - D2D1_COLOR_F color; - D2D1_BRUSH_PROPERTIES bprop; - ID2D1SolidColorBrush *brush; - HRESULT hr; - - size = realGetSize(rt); - rect.left = 0; - rect.top = 0; - rect.right = size.width; - rect.bottom = size.height; - - drawGrid(rt, &rect); - - hsv2RGB(c->h, c->s, c->v, &r, &g, &b); - color.r = r; - color.g = g; - color.b = b; - color.a = c->a; - ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); - bprop.opacity = 1.0; - bprop.transform._11 = 1; - bprop.transform._22 = 1; - hr = rt->CreateSolidColorBrush(&color, &bprop, &brush); - if (hr != S_OK) - logHRESULT(L"error creating brush for preview", hr); - rt->FillRectangle(&rect, brush); - brush->Release(); -} - -static LRESULT CALLBACK previewSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - ID2D1RenderTarget *rt; - struct colorDialog *c; - - c = (struct colorDialog *) dwRefData; - switch (uMsg) { - case msgD2DScratchPaint: - rt = (ID2D1RenderTarget *) lParam; - drawPreview(c, rt); - return 0; - case WM_NCDESTROY: - if (RemoveWindowSubclass(hwnd, previewSubProc, uIdSubclass) == FALSE) - logLastError(L"error removing color dialog previewer subclass"); - break; - } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -// once again, this is based on the Microsoft sample above -static void drawOpacitySlider(struct colorDialog *c, ID2D1RenderTarget *rt) -{ - D2D1_SIZE_F size; - D2D1_RECT_F rect; - D2D1_GRADIENT_STOP stops[2]; - ID2D1GradientStopCollection *collection; - D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lprop; - D2D1_BRUSH_PROPERTIES bprop; - ID2D1LinearGradientBrush *brush; - double hypot; - D2D1_POINT_2F center; - HRESULT hr; - - size = realGetSize(rt); - rect.left = 0; - rect.top = 0; - rect.right = size.width; - rect.bottom = size.height * (5.0 / 6.0); // bottommost sixth for arrow - - drawGrid(rt, &rect); - - stops[0].position = 0.0; - stops[0].color.r = 0.0; - stops[0].color.g = 0.0; - stops[0].color.b = 0.0; - stops[0].color.a = 1.0; - stops[1].position = 1.0; - stops[1].color.r = 1.0; // this is the XAML color Transparent, as in the source - stops[1].color.g = 1.0; - stops[1].color.b = 1.0; - stops[1].color.a = 0.0; - hr = rt->CreateGradientStopCollection(stops, 2, - // note that in this case this gamma is explicitly specified by the original - D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, - &collection); - if (hr != S_OK) - logHRESULT(L"error creating stop collection for opacity slider gradient", hr); - ZeroMemory(&lprop, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); - lprop.startPoint.x = 0; - lprop.startPoint.y = (rect.bottom - rect.top) / 2; - lprop.endPoint.x = size.width; - lprop.endPoint.y = (rect.bottom - rect.top) / 2; - ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); - bprop.opacity = 1.0; - bprop.transform._11 = 1; - bprop.transform._22 = 1; - hr = rt->CreateLinearGradientBrush(&lprop, &bprop, - collection, &brush); - if (hr != S_OK) - logHRESULT(L"error creating gradient brush for opacity slider", hr); - rt->FillRectangle(&rect, brush); - brush->Release(); - collection->Release(); - - // now draw a black arrow - center.x = (1 - c->a) * size.width; - center.y = size.height; - hypot = size.height - rect.bottom; - drawArrow(rt, center, hypot); -} - -static LRESULT CALLBACK opacitySliderSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - ID2D1RenderTarget *rt; - struct colorDialog *c; - D2D1_POINT_2F *pos; - D2D1_SIZE_F *size; - - c = (struct colorDialog *) dwRefData; - switch (uMsg) { - case msgD2DScratchPaint: - rt = (ID2D1RenderTarget *) lParam; - drawOpacitySlider(c, rt); - return 0; - case msgD2DScratchLButtonDown: - pos = (D2D1_POINT_2F *) wParam; - size = (D2D1_SIZE_F *) lParam; - c->a = 1 - (pos->x / size->width); - updateDialog(c, NULL); - return 0; - case WM_NCDESTROY: - if (RemoveWindowSubclass(hwnd, opacitySliderSubProc, uIdSubclass) == FALSE) - logLastError(L"error removing color dialog opacity slider subclass"); - break; - } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -// TODO extract into d2dscratch.cpp, use in font dialog -HWND replaceWithD2DScratch(HWND parent, int id, SUBCLASSPROC subproc, void *data) -{ - HWND replace; - RECT r; - - replace = getDlgItem(parent, id); - uiWindowsEnsureGetWindowRect(replace, &r); - mapWindowRect(NULL, parent, &r); - uiWindowsEnsureDestroyWindow(replace); - return newD2DScratch(parent, &r, (HMENU) id, subproc, (DWORD_PTR) data); - // TODO preserve Z-order -} - -// a few issues: -// - some controls are positioned wrong; see http://stackoverflow.com/questions/37263267/why-are-some-of-my-controls-positioned-slightly-off-in-a-dialog-template-in-a-re -// - labels are too low; need to adjust them by the font's internal leading -// fixupControlPositions() and the following helper routines fix that for us - -static LONG offsetTo(HWND a, HWND b) -{ - RECT ra, rb; - - uiWindowsEnsureGetWindowRect(a, &ra); - uiWindowsEnsureGetWindowRect(b, &rb); - return rb.top - ra.bottom; -} - -static void moveWindowsUp(struct colorDialog *c, LONG by, ...) -{ - va_list ap; - HWND cur; - RECT r; - - va_start(ap, by); - for (;;) { - cur = va_arg(ap, HWND); - if (cur == NULL) - break; - uiWindowsEnsureGetWindowRect(cur, &r); - mapWindowRect(NULL, c->hwnd, &r); - r.top -= by; - r.bottom -= by; - // TODO this isn't technically during a resize - uiWindowsEnsureMoveWindowDuringResize(cur, - r.left, r.top, - r.right - r.left, r.bottom - r.top); - } - va_end(ap); -} - -static void fixupControlPositions(struct colorDialog *c) -{ - HWND labelH; - HWND labelS; - HWND labelV; - HWND labelR; - HWND labelG; - HWND labelB; - HWND labelA; - HWND labelHex; - LONG offset; - uiWindowsSizing sizing; - - labelH = getDlgItem(c->hwnd, rcHLabel); - labelS = getDlgItem(c->hwnd, rcSLabel); - labelV = getDlgItem(c->hwnd, rcVLabel); - labelR = getDlgItem(c->hwnd, rcRLabel); - labelG = getDlgItem(c->hwnd, rcGLabel); - labelB = getDlgItem(c->hwnd, rcBLabel); - labelA = getDlgItem(c->hwnd, rcALabel); - labelHex = getDlgItem(c->hwnd, rcHexLabel); - - offset = offsetTo(c->editH, c->editS); - moveWindowsUp(c, offset, - labelS, c->editS, - labelG, c->editGDouble, c->editGInt, - NULL); - offset = offsetTo(c->editS, c->editV); - moveWindowsUp(c, offset, - labelV, c->editV, - labelB, c->editBDouble, c->editBInt, - NULL); - offset = offsetTo(c->editBDouble, c->editADouble); - moveWindowsUp(c, offset, - labelA, c->editADouble, c->editAInt, - NULL); - - getSizing(c->hwnd, &sizing, (HFONT) SendMessageW(labelH, WM_GETFONT, 0, 0)); - offset = sizing.InternalLeading; - moveWindowsUp(c, offset, - labelH, labelS, labelV, - labelR, labelG, labelB, labelA, - labelHex, - NULL); -} - -static struct colorDialog *beginColorDialog(HWND hwnd, LPARAM lParam) -{ - struct colorDialog *c; - - c = uiNew(struct colorDialog); - c->hwnd = hwnd; - c->out = (struct colorDialogRGBA *) lParam; - // load initial values now - rgb2HSV(c->out->r, c->out->g, c->out->b, &(c->h), &(c->s), &(c->v)); - c->a = c->out->a; - - // TODO set up d2dscratches - - // TODO prefix all these with rcColor instead of just rc - c->editH = getDlgItem(c->hwnd, rcH); - c->editS = getDlgItem(c->hwnd, rcS); - c->editV = getDlgItem(c->hwnd, rcV); - c->editRDouble = getDlgItem(c->hwnd, rcRDouble); - c->editRInt = getDlgItem(c->hwnd, rcRInt); - c->editGDouble = getDlgItem(c->hwnd, rcGDouble); - c->editGInt = getDlgItem(c->hwnd, rcGInt); - c->editBDouble = getDlgItem(c->hwnd, rcBDouble); - c->editBInt = getDlgItem(c->hwnd, rcBInt); - c->editADouble = getDlgItem(c->hwnd, rcADouble); - c->editAInt = getDlgItem(c->hwnd, rcAInt); - c->editHex = getDlgItem(c->hwnd, rcHex); - - c->svChooser = replaceWithD2DScratch(c->hwnd, rcColorSVChooser, svChooserSubProc, c); - c->hSlider = replaceWithD2DScratch(c->hwnd, rcColorHSlider, hSliderSubProc, c); - c->preview = replaceWithD2DScratch(c->hwnd, rcPreview, previewSubProc, c); - c->opacitySlider = replaceWithD2DScratch(c->hwnd, rcOpacitySlider, opacitySliderSubProc, c); - - fixupControlPositions(c); - - // and get the ball rolling - updateDialog(c, NULL); - return c; -} - -static void endColorDialog(struct colorDialog *c, INT_PTR code) -{ - if (EndDialog(c->hwnd, code) == 0) - logLastError(L"error ending color dialog"); - uiFree(c); -} - -// TODO make this void on the font dialog too -static void tryFinishDialog(struct colorDialog *c, WPARAM wParam) -{ - // cancelling - if (LOWORD(wParam) != IDOK) { - endColorDialog(c, 1); - return; - } - - // OK - hsv2RGB(c->h, c->s, c->v, &(c->out->r), &(c->out->g), &(c->out->b)); - c->out->a = c->a; - endColorDialog(c, 2); -} - -static double editDouble(HWND hwnd) -{ - WCHAR *s; - double d; - - s = windowText(hwnd); - d = _wtof(s); - uiFree(s); - return d; -} - -static void hChanged(struct colorDialog *c) -{ - double h; - - h = editDouble(c->editH); - if (h < 0 || h >= 1.0) // note the >= - return; - c->h = h; - updateDialog(c, c->editH); -} - -static void sChanged(struct colorDialog *c) -{ - double s; - - s = editDouble(c->editS); - if (s < 0 || s > 1) - return; - c->s = s; - updateDialog(c, c->editS); -} - -static void vChanged(struct colorDialog *c) -{ - double v; - - v = editDouble(c->editV); - if (v < 0 || v > 1) - return; - c->v = v; - updateDialog(c, c->editV); -} - -static void rDoubleChanged(struct colorDialog *c) -{ - double r, g, b; - - hsv2RGB(c->h, c->s, c->v, &r, &g, &b); - r = editDouble(c->editRDouble); - if (r < 0 || r > 1) - return; - rgb2HSV(r, g, b, &(c->h), &(c->s), &(c->v)); - updateDialog(c, c->editRDouble); -} - -static void gDoubleChanged(struct colorDialog *c) -{ - double r, g, b; - - hsv2RGB(c->h, c->s, c->v, &r, &g, &b); - g = editDouble(c->editGDouble); - if (g < 0 || g > 1) - return; - rgb2HSV(r, g, b, &(c->h), &(c->s), &(c->v)); - updateDialog(c, c->editGDouble); -} - -static void bDoubleChanged(struct colorDialog *c) -{ - double r, g, b; - - hsv2RGB(c->h, c->s, c->v, &r, &g, &b); - b = editDouble(c->editBDouble); - if (b < 0 || b > 1) - return; - rgb2HSV(r, g, b, &(c->h), &(c->s), &(c->v)); - updateDialog(c, c->editBDouble); -} - -static void aDoubleChanged(struct colorDialog *c) -{ - double a; - - a = editDouble(c->editADouble); - if (a < 0 || a > 1) - return; - c->a = a; - updateDialog(c, c->editADouble); -} - -static int editInt(HWND hwnd) -{ - WCHAR *s; - int i; - - s = windowText(hwnd); - i = _wtoi(s); - uiFree(s); - return i; -} - -static void rIntChanged(struct colorDialog *c) -{ - double r, g, b; - int i; - - hsv2RGB(c->h, c->s, c->v, &r, &g, &b); - i = editInt(c->editRInt); - if (i < 0 || i > 255) - return; - r = ((double) i) / 255.0; - rgb2HSV(r, g, b, &(c->h), &(c->s), &(c->v)); - updateDialog(c, c->editRInt); -} - -static void gIntChanged(struct colorDialog *c) -{ - double r, g, b; - int i; - - hsv2RGB(c->h, c->s, c->v, &r, &g, &b); - i = editInt(c->editGInt); - if (i < 0 || i > 255) - return; - g = ((double) i) / 255.0; - rgb2HSV(r, g, b, &(c->h), &(c->s), &(c->v)); - updateDialog(c, c->editGInt); -} - -static void bIntChanged(struct colorDialog *c) -{ - double r, g, b; - int i; - - hsv2RGB(c->h, c->s, c->v, &r, &g, &b); - i = editInt(c->editBInt); - if (i < 0 || i > 255) - return; - b = ((double) i) / 255.0; - rgb2HSV(r, g, b, &(c->h), &(c->s), &(c->v)); - updateDialog(c, c->editBInt); -} - -static void aIntChanged(struct colorDialog *c) -{ - int a; - - a = editInt(c->editAInt); - if (a < 0 || a > 255) - return; - c->a = ((double) a) / 255; - updateDialog(c, c->editAInt); -} - -static void hexChanged(struct colorDialog *c) -{ - WCHAR *buf; - double r, g, b, a; - BOOL is; - - buf = windowText(c->editHex); - is = hex2RGBA(buf, &r, &g, &b, &a); - uiFree(buf); - if (!is) - return; - rgb2HSV(r, g, b, &(c->h), &(c->s), &(c->v)); - c->a = a; - updateDialog(c, c->editHex); -} - -// TODO change fontdialog to use this -// note that if we make this const, we get lots of weird compiler errors -static std::map changed = { - { rcH, hChanged }, - { rcS, sChanged }, - { rcV, vChanged }, - { rcRDouble, rDoubleChanged }, - { rcGDouble, gDoubleChanged }, - { rcBDouble, bDoubleChanged }, - { rcADouble, aDoubleChanged }, - { rcRInt, rIntChanged }, - { rcGInt, gIntChanged }, - { rcBInt, bIntChanged }, - { rcAInt, aIntChanged }, - { rcHex, hexChanged }, -}; - -static INT_PTR CALLBACK colorDialogDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - struct colorDialog *c; - - c = (struct colorDialog *) GetWindowLongPtrW(hwnd, DWLP_USER); - if (c == NULL) { - if (uMsg == WM_INITDIALOG) { - c = beginColorDialog(hwnd, lParam); - SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR) c); - return TRUE; - } - return FALSE; - } - - switch (uMsg) { - case WM_COMMAND: - SetWindowLongPtrW(c->hwnd, DWLP_MSGRESULT, 0); // just in case - switch (LOWORD(wParam)) { - case IDOK: - case IDCANCEL: - if (HIWORD(wParam) != BN_CLICKED) - return FALSE; - tryFinishDialog(c, wParam); - return TRUE; - case rcH: - case rcS: - case rcV: - case rcRDouble: - case rcGDouble: - case rcBDouble: - case rcADouble: - case rcRInt: - case rcGInt: - case rcBInt: - case rcAInt: - case rcHex: - if (HIWORD(wParam) != EN_CHANGE) - return FALSE; - if (c->updating) // prevent infinite recursion during an update - return FALSE; - (*(changed[LOWORD(wParam)]))(c); - return TRUE; - } - return FALSE; - } - return FALSE; -} - -BOOL showColorDialog(HWND parent, struct colorDialogRGBA *c) -{ - switch (DialogBoxParamW(hInstance, MAKEINTRESOURCE(rcColorDialog), parent, colorDialogDlgProc, (LPARAM) c)) { - case 1: // cancel - return FALSE; - case 2: // ok - // make the compiler happy by putting the return after the switch - break; - default: - logLastError(L"error running color dialog"); - } - return TRUE; -} diff --git a/deps/libui/windows/combobox.cpp b/deps/libui/windows/combobox.cpp deleted file mode 100644 index 87c999ea3a..0000000000 --- a/deps/libui/windows/combobox.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// 20 may 2015 -#include "uipriv_windows.hpp" - -// we as Common Controls 6 users don't need to worry about the height of comboboxes; see http://blogs.msdn.com/b/oldnewthing/archive/2006/03/10/548537.aspx - -struct uiCombobox { - uiWindowsControl c; - HWND hwnd; - void (*onSelected)(uiCombobox *, void *); - void *onSelectedData; -}; - -static BOOL onWM_COMMAND(uiControl *cc, HWND hwnd, WORD code, LRESULT *lResult) -{ - uiCombobox *c = uiCombobox(cc); - - if (code != CBN_SELCHANGE) - return FALSE; - (*(c->onSelected))(c, c->onSelectedData); - *lResult = 0; - return TRUE; -} - -void uiComboboxDestroy(uiControl *cc) -{ - uiCombobox *c = uiCombobox(cc); - - uiWindowsUnregisterWM_COMMANDHandler(c->hwnd); - uiWindowsEnsureDestroyWindow(c->hwnd); - uiFreeControl(uiControl(c)); -} - -uiWindowsControlAllDefaultsExceptDestroy(uiCombobox) - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define comboboxWidth 107 /* this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary; LONGTERM */ -#define comboboxHeight 14 /* LONGTERM: is this too high? */ - -static void uiComboboxMinimumSize(uiWindowsControl *cc, int *width, int *height) -{ - uiCombobox *c = uiCombobox(cc); - uiWindowsSizing sizing; - int x, y; - - x = comboboxWidth; - y = comboboxHeight; - uiWindowsGetSizing(c->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - *width = x; - *height = y; -} - -static void defaultOnSelected(uiCombobox *c, void *data) -{ - // do nothing -} - -void uiComboboxAppend(uiCombobox *c, const char *text) -{ - WCHAR *wtext; - LRESULT res; - - wtext = toUTF16(text); - res = SendMessageW(c->hwnd, CB_ADDSTRING, 0, (LPARAM) wtext); - if (res == (LRESULT) CB_ERR) - logLastError(L"error appending item to uiCombobox"); - else if (res == (LRESULT) CB_ERRSPACE) - logLastError(L"memory exhausted appending item to uiCombobox"); - uiFree(wtext); -} - -int uiComboboxSelected(uiCombobox *c) -{ - LRESULT n; - - n = SendMessage(c->hwnd, CB_GETCURSEL, 0, 0); - if (n == (LRESULT) CB_ERR) - return -1; - return n; -} - -void uiComboboxSetSelected(uiCombobox *c, int n) -{ - // TODO error check - SendMessageW(c->hwnd, CB_SETCURSEL, (WPARAM) n, 0); -} - -void uiComboboxOnSelected(uiCombobox *c, void (*f)(uiCombobox *c, void *data), void *data) -{ - c->onSelected = f; - c->onSelectedData = data; -} - -uiCombobox *uiNewCombobox(void) -{ - uiCombobox *c; - - uiWindowsNewControl(uiCombobox, c); - - c->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE, - L"combobox", L"", - CBS_DROPDOWNLIST | WS_TABSTOP, - hInstance, NULL, - TRUE); - - uiWindowsRegisterWM_COMMANDHandler(c->hwnd, onWM_COMMAND, uiControl(c)); - uiComboboxOnSelected(c, defaultOnSelected, NULL); - - return c; -} diff --git a/deps/libui/windows/compilerver.hpp b/deps/libui/windows/compilerver.hpp deleted file mode 100644 index 6c9e6b815a..0000000000 --- a/deps/libui/windows/compilerver.hpp +++ /dev/null @@ -1,13 +0,0 @@ -// 9 june 2015 - -// Visual Studio (Microsoft's compilers) -// VS2013 is needed for va_copy(). -#ifdef _MSC_VER -#if _MSC_VER < 1800 -#error Visual Studio 2013 or higher is required to build libui. -#endif -#endif - -// LONGTERM MinGW - -// other compilers can be added here as necessary diff --git a/deps/libui/windows/container.cpp b/deps/libui/windows/container.cpp deleted file mode 100644 index 9ec1e2803c..0000000000 --- a/deps/libui/windows/container.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// 26 april 2015 -#include "uipriv_windows.hpp" - -// Code for the HWND of the following uiControls: -// - uiBox -// - uiRadioButtons -// - uiSpinbox -// - uiTab -// - uiForm -// - uiGrid - -struct containerInit { - uiWindowsControl *c; - void (*onResize)(uiWindowsControl *); -}; - -static LRESULT CALLBACK containerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - RECT r; - HDC dc; - PAINTSTRUCT ps; - CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; - WINDOWPOS *wp = (WINDOWPOS *) lParam; - MINMAXINFO *mmi = (MINMAXINFO *) lParam; - struct containerInit *init; - uiWindowsControl *c; - void (*onResize)(uiWindowsControl *); - int minwid, minht; - LRESULT lResult; - - if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE) - return lResult; - switch (uMsg) { - case WM_CREATE: - init = (struct containerInit *) (cs->lpCreateParams); - SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) (init->onResize)); - SetWindowLongPtrW(hwnd, 0, (LONG_PTR) (init->c)); - break; // defer to DefWindowProc() - case WM_WINDOWPOSCHANGED: - if ((wp->flags & SWP_NOSIZE) != 0) - break; // defer to DefWindowProc(); - onResize = (void (*)(uiWindowsControl *)) GetWindowLongPtrW(hwnd, GWLP_USERDATA); - c = (uiWindowsControl *) GetWindowLongPtrW(hwnd, 0); - (*(onResize))(c); - return 0; - case WM_GETMINMAXINFO: - lResult = DefWindowProcW(hwnd, uMsg, wParam, lParam); - c = (uiWindowsControl *) GetWindowLongPtrW(hwnd, 0); - uiWindowsControlMinimumSize(c, &minwid, &minht); - mmi->ptMinTrackSize.x = minwid; - mmi->ptMinTrackSize.y = minht; - return lResult; - case WM_PAINT: - dc = BeginPaint(hwnd, &ps); - if (dc == NULL) { - logLastError(L"error beginning container paint"); - // bail out; hope DefWindowProc() catches us - break; - } - r = ps.rcPaint; - paintContainerBackground(hwnd, dc, &r); - EndPaint(hwnd, &ps); - return 0; - // tab controls use this to draw the background of the tab area - case WM_PRINTCLIENT: - uiWindowsEnsureGetClientRect(hwnd, &r); - paintContainerBackground(hwnd, (HDC) wParam, &r); - return 0; - case WM_ERASEBKGND: - // avoid some flicker - // we draw the whole update area anyway - return 1; - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - -ATOM initContainer(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = containerClass; - wc.lpfnWndProc = containerWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - wc.cbWndExtra = sizeof (void *); - return RegisterClassW(&wc); -} - -void uninitContainer(void) -{ - if (UnregisterClassW(containerClass, hInstance) == 0) - logLastError(L"error unregistering container window class"); -} - -HWND uiWindowsMakeContainer(uiWindowsControl *c, void (*onResize)(uiWindowsControl *)) -{ - struct containerInit init; - - // TODO onResize cannot be NULL - init.c = c; - init.onResize = onResize; - return uiWindowsEnsureCreateControlHWND(WS_EX_CONTROLPARENT, - containerClass, L"", - 0, - hInstance, (LPVOID) (&init), - FALSE); -} diff --git a/deps/libui/windows/control.cpp b/deps/libui/windows/control.cpp deleted file mode 100644 index ce953cf941..0000000000 --- a/deps/libui/windows/control.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// 16 august 2015 -#include "uipriv_windows.hpp" - -void uiWindowsControlSyncEnableState(uiWindowsControl *c, int enabled) -{ - (*(c->SyncEnableState))(c, enabled); -} - -void uiWindowsControlSetParentHWND(uiWindowsControl *c, HWND parent) -{ - (*(c->SetParentHWND))(c, parent); -} - -void uiWindowsControlMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - (*(c->MinimumSize))(c, width, height); -} - -void uiWindowsControlMinimumSizeChanged(uiWindowsControl *c) -{ - (*(c->MinimumSizeChanged))(c); -} - -// TODO get rid of this -void uiWindowsControlLayoutRect(uiWindowsControl *c, RECT *r) -{ - (*(c->LayoutRect))(c, r); -} - -void uiWindowsControlAssignControlIDZOrder(uiWindowsControl *c, LONG_PTR *controlID, HWND *insertAfter) -{ - (*(c->AssignControlIDZOrder))(c, controlID, insertAfter); -} - -void uiWindowsControlChildVisibilityChanged(uiWindowsControl *c) -{ - (*(c->ChildVisibilityChanged))(c); -} - -HWND uiWindowsEnsureCreateControlHWND(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, HINSTANCE hInstance, LPVOID lpParam, BOOL useStandardControlFont) -{ - HWND hwnd; - - // don't let using the arrow keys in a uiRadioButtons leave the radio buttons - if ((dwStyle & WS_TABSTOP) != 0) - dwStyle |= WS_GROUP; - hwnd = CreateWindowExW(dwExStyle, - lpClassName, lpWindowName, - dwStyle | WS_CHILD | WS_VISIBLE, - 0, 0, - // use a nonzero initial size just in case some control breaks with a zero initial size - 100, 100, - utilWindow, NULL, hInstance, lpParam); - if (hwnd == NULL) { - logLastError(L"error creating window"); - // TODO return a decoy window - } - if (useStandardControlFont) - SendMessageW(hwnd, WM_SETFONT, (WPARAM) hMessageFont, (LPARAM) TRUE); - return hwnd; -} - -// choose a value distinct from uiWindowSignature -#define uiWindowsControlSignature 0x4D53576E - -uiWindowsControl *uiWindowsAllocControl(size_t n, uint32_t typesig, const char *typenamestr) -{ - return uiWindowsControl(uiAllocControl(n, uiWindowsControlSignature, typesig, typenamestr)); -} - -BOOL uiWindowsShouldStopSyncEnableState(uiWindowsControl *c, BOOL enabled) -{ - int ce; - - ce = uiControlEnabled(uiControl(c)); - // only stop if we're going from disabled back to enabled; don't stop under any other condition - // (if we stop when going from enabled to disabled then enabled children of a disabled control won't get disabled at the OS level) - if (!ce && enabled) - return TRUE; - return FALSE; -} - -void uiWindowsControlAssignSoleControlIDZOrder(uiWindowsControl *c) -{ - LONG_PTR controlID; - HWND insertAfter; - - controlID = 100; - insertAfter = NULL; - uiWindowsControlAssignControlIDZOrder(c, &controlID, &insertAfter); -} - -BOOL uiWindowsControlTooSmall(uiWindowsControl *c) -{ - RECT r; - int width, height; - - uiWindowsControlLayoutRect(c, &r); - uiWindowsControlMinimumSize(c, &width, &height); - if ((r.right - r.left) < width) - return TRUE; - if ((r.bottom - r.top) < height) - return TRUE; - return FALSE; -} - -void uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl *c) -{ - uiControl *parent; - - parent = uiControlParent(uiControl(c)); - if (parent != NULL) - uiWindowsControlMinimumSizeChanged(uiWindowsControl(parent)); -} - -// TODO rename this nad the OS X this and hugging ones to NotifyChild -void uiWindowsControlNotifyVisibilityChanged(uiWindowsControl *c) -{ - // TODO we really need to figure this out; the duplication is a mess - uiWindowsControlContinueMinimumSizeChanged(c); -} diff --git a/deps/libui/windows/d2dscratch.cpp b/deps/libui/windows/d2dscratch.cpp deleted file mode 100644 index 6dc2ba5fd3..0000000000 --- a/deps/libui/windows/d2dscratch.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// 17 april 2016 -#include "uipriv_windows.hpp" - -// The Direct2D scratch window is a utility for libui internal use to do quick things with Direct2D. -// To use, call newD2DScratch() passing in a subclass procedure. This subclass procedure should handle the msgD2DScratchPaint message, which has the following usage: -// - wParam - 0 -// - lParam - ID2D1RenderTarget * -// - lResult - 0 -// You can optionally also handle msgD2DScratchLButtonDown, which is sent when the left mouse button is either pressed for the first time or held while the mouse is moving. -// - wParam - position in DIPs, as D2D1_POINT_2F * -// - lParam - size of render target in DIPs, as D2D1_SIZE_F * -// - lResult - 0 -// Other messages can also be handled here. - -// TODO allow resize - -#define d2dScratchClass L"libui_d2dScratchClass" - -// TODO clip rect -static HRESULT d2dScratchDoPaint(HWND hwnd, ID2D1RenderTarget *rt) -{ - COLORREF bgcolorref; - D2D1_COLOR_F bgcolor; - - rt->BeginDraw(); - - // TODO only clear the clip area - // TODO clear with actual background brush - bgcolorref = GetSysColor(COLOR_BTNFACE); - bgcolor.r = ((float) GetRValue(bgcolorref)) / 255.0; - // due to utter apathy on Microsoft's part, GetGValue() does not work with MSVC's Run-Time Error Checks - // it has not worked since 2008 and they have *never* fixed it - // TODO now that -RTCc has just been deprecated entirely, should we switch back? - bgcolor.g = ((float) ((BYTE) ((bgcolorref & 0xFF00) >> 8))) / 255.0; - bgcolor.b = ((float) GetBValue(bgcolorref)) / 255.0; - bgcolor.a = 1.0; - rt->Clear(&bgcolor); - - SendMessageW(hwnd, msgD2DScratchPaint, 0, (LPARAM) rt); - - return rt->EndDraw(NULL, NULL); -} - -static void d2dScratchDoLButtonDown(HWND hwnd, ID2D1RenderTarget *rt, LPARAM lParam) -{ - double xpix, ypix; - FLOAT dpix, dpiy; - D2D1_POINT_2F pos; - D2D1_SIZE_F size; - - xpix = (double) GET_X_LPARAM(lParam); - ypix = (double) GET_Y_LPARAM(lParam); - // these are in pixels; we need points - // TODO separate the function from areautil.cpp? - rt->GetDpi(&dpix, &dpiy); - pos.x = (xpix * 96) / dpix; - pos.y = (ypix * 96) / dpiy; - - size = realGetSize(rt); - - SendMessageW(hwnd, msgD2DScratchLButtonDown, (WPARAM) (&pos), (LPARAM) (&size)); -} - -static LRESULT CALLBACK d2dScratchWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - LONG_PTR init; - ID2D1HwndRenderTarget *rt; - ID2D1DCRenderTarget *dcrt; - RECT client; - HRESULT hr; - - init = GetWindowLongPtrW(hwnd, 0); - if (!init) { - if (uMsg == WM_CREATE) - SetWindowLongPtrW(hwnd, 0, (LONG_PTR) TRUE); - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } - - rt = (ID2D1HwndRenderTarget *) GetWindowLongPtrW(hwnd, GWLP_USERDATA); - if (rt == NULL) { - rt = makeHWNDRenderTarget(hwnd); - SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) rt); - } - - switch (uMsg) { - case WM_DESTROY: - rt->Release(); - SetWindowLongPtrW(hwnd, 0, (LONG_PTR) FALSE); - break; - case WM_PAINT: - hr = d2dScratchDoPaint(hwnd, rt); - switch (hr) { - case S_OK: - if (ValidateRect(hwnd, NULL) == 0) - logLastError(L"error validating D2D scratch control rect"); - break; - case D2DERR_RECREATE_TARGET: - // DON'T validate the rect - // instead, simply drop the render target - // we'll get another WM_PAINT and make the render target again - // TODO would this require us to invalidate the entire client area? - rt->Release(); - SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) NULL); - break; - default: - logHRESULT(L"error drawing D2D scratch window", hr); - } - return 0; - case WM_PRINTCLIENT: - uiWindowsEnsureGetClientRect(hwnd, &client); - dcrt = makeHDCRenderTarget((HDC) wParam, &client); - hr = d2dScratchDoPaint(hwnd, dcrt); - if (hr != S_OK) - logHRESULT(L"error printing D2D scratch window client area", hr); - dcrt->Release(); - return 0; - case WM_LBUTTONDOWN: - d2dScratchDoLButtonDown(hwnd, rt, lParam); - return 0; - case WM_MOUSEMOVE: - // also send LButtonDowns when dragging - if ((wParam & MK_LBUTTON) != 0) - d2dScratchDoLButtonDown(hwnd, rt, lParam); - return 0; - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - -ATOM registerD2DScratchClass(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = d2dScratchClass; - wc.lpfnWndProc = d2dScratchWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - wc.cbWndExtra = sizeof (LONG_PTR); // for the init status - return RegisterClassW(&wc); -} - -void unregisterD2DScratchClass(void) -{ - if (UnregisterClassW(d2dScratchClass, hInstance) == 0) - logLastError(L"error unregistering D2D scratch window class"); -} - -HWND newD2DScratch(HWND parent, RECT *rect, HMENU controlID, SUBCLASSPROC subclass, DWORD_PTR subclassData) -{ - HWND hwnd; - - hwnd = CreateWindowExW(0, - d2dScratchClass, L"", - WS_CHILD | WS_VISIBLE, - rect->left, rect->top, - rect->right - rect->left, rect->bottom - rect->top, - parent, controlID, hInstance, NULL); - if (hwnd == NULL) - // TODO return decoy window - logLastError(L"error creating D2D scratch window"); - if (SetWindowSubclass(hwnd, subclass, 0, subclassData) == FALSE) - logLastError(L"error subclassing D2D scratch window"); - return hwnd; -} diff --git a/deps/libui/windows/datetimepicker.cpp b/deps/libui/windows/datetimepicker.cpp deleted file mode 100644 index e105c2fdb7..0000000000 --- a/deps/libui/windows/datetimepicker.cpp +++ /dev/null @@ -1,191 +0,0 @@ -// 22 may 2015 -#include "uipriv_windows.hpp" - -struct uiDateTimePicker { - uiWindowsControl c; - HWND hwnd; -}; - -// utility functions - -#define GLI(what, buf, n) GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, what, buf, n) - -// The real date/time picker does a manual replacement of "yy" with "yyyy" for DTS_SHORTDATECENTURYFORMAT. -// Because we're also duplicating its functionality (see below), we have to do it too. -static WCHAR *expandYear(WCHAR *dts, int n) -{ - WCHAR *out; - WCHAR *p, *q; - int ny = 0; - - // allocate more than we need to be safe - out = (WCHAR *) uiAlloc((n * 3) * sizeof (WCHAR), "WCHAR[]"); - q = out; - for (p = dts; *p != L'\0'; p++) { - // first, if the current character is a y, increment the number of consecutive ys - // otherwise, stop counting, and if there were only two, add two more to make four - if (*p != L'y') { - if (ny == 2) { - *q++ = L'y'; - *q++ = L'y'; - } - ny = 0; - } else - ny++; - // next, handle quoted blocks - // we do this AFTER the above so yy'abc' becomes yyyy'abc' and not yy'abc'yy - // this handles the case of 'a''b' elegantly as well - if (*p == L'\'') { - // copy the opening quote - *q++ = *p; - // copy the contents - for (;;) { - p++; - if (*p == L'\'') - break; - if (*p == L'\0') - implbug("unterminated quote in system-provided locale date string in expandYear()"); - *q++ = *p; - } - // and fall through to copy the closing quote - } - // copy the current character - *q++ = *p; - } - // handle trailing yy - if (ny == 2) { - *q++ = L'y'; - *q++ = L'y'; - } - *q++ = L'\0'; - return out; -} - -// Windows has no combined date/time prebuilt constant; we have to build the format string ourselves -// TODO use a default format if one fails -static void setDateTimeFormat(HWND hwnd) -{ - WCHAR *unexpandedDate, *date; - WCHAR *time; - WCHAR *datetime; - int ndate, ntime; - - ndate = GLI(LOCALE_SSHORTDATE, NULL, 0); - if (ndate == 0) - logLastError(L"error getting date string length"); - date = (WCHAR *) uiAlloc(ndate * sizeof (WCHAR), "WCHAR[]"); - if (GLI(LOCALE_SSHORTDATE, date, ndate) == 0) - logLastError(L"error geting date string"); - unexpandedDate = date; // so we can free it - date = expandYear(unexpandedDate, ndate); - uiFree(unexpandedDate); - - ntime = GLI(LOCALE_STIMEFORMAT, NULL, 0); - if (ndate == 0) - logLastError(L"error getting time string length"); - time = (WCHAR *) uiAlloc(ntime * sizeof (WCHAR), "WCHAR[]"); - if (GLI(LOCALE_STIMEFORMAT, time, ntime) == 0) - logLastError(L"error geting time string"); - - datetime = strf(L"%s %s", date, time); - if (SendMessageW(hwnd, DTM_SETFORMAT, 0, (LPARAM) datetime) == 0) - logLastError(L"error applying format string to date/time picker"); - - uiFree(datetime); - uiFree(time); - uiFree(date); -} - -// control implementation - -static void uiDateTimePickerDestroy(uiControl *c) -{ - uiDateTimePicker *d = uiDateTimePicker(c); - - uiWindowsUnregisterReceiveWM_WININICHANGE(d->hwnd); - uiWindowsEnsureDestroyWindow(d->hwnd); - uiFreeControl(uiControl(d)); -} - -uiWindowsControlAllDefaultsExceptDestroy(uiDateTimePicker) - -// the height returned from DTM_GETIDEALSIZE is unreliable; see http://stackoverflow.com/questions/30626549/what-is-the-proper-use-of-dtm-getidealsize-treating-the-returned-size-as-pixels -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define entryHeight 14 - -static void uiDateTimePickerMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiDateTimePicker *d = uiDateTimePicker(c); - SIZE s; - uiWindowsSizing sizing; - int y; - - s.cx = 0; - s.cy = 0; - SendMessageW(d->hwnd, DTM_GETIDEALSIZE, 0, (LPARAM) (&s)); - *width = s.cx; - - y = entryHeight; - uiWindowsGetSizing(d->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &y); - *height = y; -} - -static uiDateTimePicker *finishNewDateTimePicker(DWORD style) -{ - uiDateTimePicker *d; - - uiWindowsNewControl(uiDateTimePicker, d); - - d->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE, - DATETIMEPICK_CLASSW, L"", - style | WS_TABSTOP, - hInstance, NULL, - TRUE); - - // automatically update date/time format when user changes locale settings - // for the standard styles, this is in the date-time picker itself - // for our date/time mode, we do it in a subclass assigned in uiNewDateTimePicker() - uiWindowsRegisterReceiveWM_WININICHANGE(d->hwnd); - - return d; -} - -static LRESULT CALLBACK datetimepickerSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - switch (uMsg) { - case WM_WININICHANGE: - // we can optimize this by only doing it when the real date/time picker does it - // unfortunately, I don't know when that is :/ - // hopefully this won't hurt - setDateTimeFormat(hwnd); - return 0; - case WM_NCDESTROY: - if (RemoveWindowSubclass(hwnd, datetimepickerSubProc, uIdSubclass) == FALSE) - logLastError(L"error removing date-time picker locale change handling subclass"); - break; - } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -uiDateTimePicker *uiNewDateTimePicker(void) -{ - uiDateTimePicker *d; - - d = finishNewDateTimePicker(0); - setDateTimeFormat(d->hwnd); - if (SetWindowSubclass(d->hwnd, datetimepickerSubProc, 0, (DWORD_PTR) d) == FALSE) - logLastError(L"error subclassing date-time-picker to assist in locale change handling"); - // TODO set a suitable default in this case - return d; -} - -uiDateTimePicker *uiNewDatePicker(void) -{ - return finishNewDateTimePicker(DTS_SHORTDATECENTURYFORMAT); -} - -uiDateTimePicker *uiNewTimePicker(void) -{ - return finishNewDateTimePicker(DTS_TIMEFORMAT); -} diff --git a/deps/libui/windows/debug.cpp b/deps/libui/windows/debug.cpp deleted file mode 100644 index cfafffdc86..0000000000 --- a/deps/libui/windows/debug.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// 25 february 2015 -#include "uipriv_windows.hpp" - -// LONGTERM disable logging and stopping on no-debug builds - -static void printDebug(const WCHAR *msg) -{ - OutputDebugStringW(msg); -} - -HRESULT _logLastError(debugargs, const WCHAR *s) -{ - DWORD le; - WCHAR *msg; - WCHAR *formatted; - BOOL useFormatted; - - le = GetLastError(); - - useFormatted = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, le, 0, (LPWSTR) (&formatted), 0, NULL) != 0; - if (!useFormatted) - formatted = L"\n"; - msg = strf(L"[libui] %s:%s:%s() %s: GetLastError() == %I32u %s", - file, line, func, - s, le, formatted); - if (useFormatted) - LocalFree(formatted); // ignore error - printDebug(msg); - uiFree(msg); - DebugBreak(); - - SetLastError(le); - // a function does not have to set a last error - // if the last error we get is actually 0, then HRESULT_FROM_WIN32(0) will return S_OK (0 cast to an HRESULT, since 0 <= 0), which we don't want - // prevent this by returning E_FAIL - if (le == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(le); -} - -HRESULT _logHRESULT(debugargs, const WCHAR *s, HRESULT hr) -{ - WCHAR *msg; - WCHAR *formatted; - BOOL useFormatted; - - useFormatted = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, hr, 0, (LPWSTR) (&formatted), 0, NULL) != 0; - if (!useFormatted) - formatted = L"\n"; - msg = strf(L"[libui] %s:%s:%s() %s: HRESULT == 0x%08I32X %s", - file, line, func, - s, hr, formatted); - if (useFormatted) - LocalFree(formatted); // ignore error - printDebug(msg); - uiFree(msg); - DebugBreak(); - - return hr; -} - -void realbug(const char *file, const char *line, const char *func, const char *prefix, const char *format, va_list ap) -{ - va_list ap2; - char *msg; - size_t n; - WCHAR *final; - - va_copy(ap2, ap); - n = _vscprintf(format, ap2); - va_end(ap2); - n++; // terminating '\0' - - msg = (char *) uiAlloc(n * sizeof (char), "char[]"); - // includes terminating '\0' according to example in https://msdn.microsoft.com/en-us/library/xa1a1a6z.aspx - vsprintf_s(msg, n, format, ap); - - final = strf(L"[libui] %hs:%hs:%hs() %hs%hs\n", file, line, func, prefix, msg); - uiFree(msg); - printDebug(final); - uiFree(final); - - DebugBreak(); -} diff --git a/deps/libui/windows/draw.cpp b/deps/libui/windows/draw.cpp deleted file mode 100644 index 5f4d29f1a0..0000000000 --- a/deps/libui/windows/draw.cpp +++ /dev/null @@ -1,511 +0,0 @@ -// 7 september 2015 -#include "uipriv_windows.hpp" -#include "draw.hpp" - -ID2D1Factory *d2dfactory = NULL; - -HRESULT initDraw(void) -{ - D2D1_FACTORY_OPTIONS opts; - - ZeroMemory(&opts, sizeof (D2D1_FACTORY_OPTIONS)); - // TODO make this an option - opts.debugLevel = D2D1_DEBUG_LEVEL_NONE; - return D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, - IID_ID2D1Factory, - &opts, - (void **) (&d2dfactory)); -} - -void uninitDraw(void) -{ - d2dfactory->Release(); -} - -ID2D1HwndRenderTarget *makeHWNDRenderTarget(HWND hwnd) -{ - D2D1_RENDER_TARGET_PROPERTIES props; - D2D1_HWND_RENDER_TARGET_PROPERTIES hprops; - HDC dc; - RECT r; - ID2D1HwndRenderTarget *rt; - HRESULT hr; - - // we need a DC for the DPI - // we *could* just use the screen DPI but why when we have a window handle and its DC has a DPI - dc = GetDC(hwnd); - if (dc == NULL) - logLastError(L"error getting DC to find DPI"); - - ZeroMemory(&props, sizeof (D2D1_RENDER_TARGET_PROPERTIES)); - props.type = D2D1_RENDER_TARGET_TYPE_DEFAULT; - props.pixelFormat.format = DXGI_FORMAT_UNKNOWN; - props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN; - props.dpiX = GetDeviceCaps(dc, LOGPIXELSX); - props.dpiY = GetDeviceCaps(dc, LOGPIXELSY); - props.usage = D2D1_RENDER_TARGET_USAGE_NONE; - props.minLevel = D2D1_FEATURE_LEVEL_DEFAULT; - - if (ReleaseDC(hwnd, dc) == 0) - logLastError(L"error releasing DC for finding DPI"); - - uiWindowsEnsureGetClientRect(hwnd, &r); - - ZeroMemory(&hprops, sizeof (D2D1_HWND_RENDER_TARGET_PROPERTIES)); - hprops.hwnd = hwnd; - hprops.pixelSize.width = r.right - r.left; - hprops.pixelSize.height = r.bottom - r.top; - // according to Rick Brewster, some drivers will misbehave if we don't specify this (see http://stackoverflow.com/a/33222983/3408572) - hprops.presentOptions = D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS; - - hr = d2dfactory->CreateHwndRenderTarget( - &props, - &hprops, - &rt); - if (hr != S_OK) - logHRESULT(L"error creating HWND render target", hr); - return rt; -} - -ID2D1DCRenderTarget *makeHDCRenderTarget(HDC dc, RECT *r) -{ - D2D1_RENDER_TARGET_PROPERTIES props; - ID2D1DCRenderTarget *rt; - HRESULT hr; - - ZeroMemory(&props, sizeof (D2D1_RENDER_TARGET_PROPERTIES)); - props.type = D2D1_RENDER_TARGET_TYPE_DEFAULT; - props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; - props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; - props.dpiX = GetDeviceCaps(dc, LOGPIXELSX); - props.dpiY = GetDeviceCaps(dc, LOGPIXELSY); - props.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE; - props.minLevel = D2D1_FEATURE_LEVEL_DEFAULT; - - hr = d2dfactory->CreateDCRenderTarget(&props, &rt); - if (hr != S_OK) - logHRESULT(L"error creating DC render target", hr); - hr = rt->BindDC(dc, r); - if (hr != S_OK) - logHRESULT(L"error binding DC to DC render target", hr); - return rt; -} - -static void resetTarget(ID2D1RenderTarget *rt) -{ - D2D1_MATRIX_3X2_F dm; - - // transformations persist - // reset to the identity matrix - ZeroMemory(&dm, sizeof (D2D1_MATRIX_3X2_F)); - dm._11 = 1; - dm._22 = 1; - rt->SetTransform(&dm); -} - -uiDrawContext *newContext(ID2D1RenderTarget *rt) -{ - uiDrawContext *c; - - c = uiNew(uiDrawContext); - c->rt = rt; - c->states = new std::vector; - resetTarget(c->rt); - return c; -} - -void freeContext(uiDrawContext *c) -{ - if (c->currentClip != NULL) - c->currentClip->Release(); - if (c->states->size() != 0) - // TODO do this on other platforms - userbug("You did not balance uiDrawSave() and uiDrawRestore() calls."); - delete c->states; - uiFree(c); -} - -static ID2D1Brush *makeSolidBrush(uiDrawBrush *b, ID2D1RenderTarget *rt, D2D1_BRUSH_PROPERTIES *props) -{ - D2D1_COLOR_F color; - ID2D1SolidColorBrush *brush; - HRESULT hr; - - color.r = b->R; - color.g = b->G; - color.b = b->B; - color.a = b->A; - - hr = rt->CreateSolidColorBrush( - &color, - props, - &brush); - if (hr != S_OK) - logHRESULT(L"error creating solid brush", hr); - return brush; -} - -static ID2D1GradientStopCollection *mkstops(uiDrawBrush *b, ID2D1RenderTarget *rt) -{ - ID2D1GradientStopCollection *s; - D2D1_GRADIENT_STOP *stops; - size_t i; - HRESULT hr; - - stops = (D2D1_GRADIENT_STOP *) uiAlloc(b->NumStops * sizeof (D2D1_GRADIENT_STOP), "D2D1_GRADIENT_STOP[]"); - for (i = 0; i < b->NumStops; i++) { - stops[i].position = b->Stops[i].Pos; - stops[i].color.r = b->Stops[i].R; - stops[i].color.g = b->Stops[i].G; - stops[i].color.b = b->Stops[i].B; - stops[i].color.a = b->Stops[i].A; - } - - hr = rt->CreateGradientStopCollection( - stops, - b->NumStops, - D2D1_GAMMA_2_2, // this is the default for the C++-only overload of ID2D1RenderTarget::GradientStopCollection() - D2D1_EXTEND_MODE_CLAMP, - &s); - if (hr != S_OK) - logHRESULT(L"error creating stop collection", hr); - - uiFree(stops); - return s; -} - -static ID2D1Brush *makeLinearBrush(uiDrawBrush *b, ID2D1RenderTarget *rt, D2D1_BRUSH_PROPERTIES *props) -{ - ID2D1LinearGradientBrush *brush; - D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES gprops; - ID2D1GradientStopCollection *stops; - HRESULT hr; - - ZeroMemory(&gprops, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); - gprops.startPoint.x = b->X0; - gprops.startPoint.y = b->Y0; - gprops.endPoint.x = b->X1; - gprops.endPoint.y = b->Y1; - - stops = mkstops(b, rt); - - hr = rt->CreateLinearGradientBrush( - &gprops, - props, - stops, - &brush); - if (hr != S_OK) - logHRESULT(L"error creating gradient brush", hr); - - // the example at https://msdn.microsoft.com/en-us/library/windows/desktop/dd756682%28v=vs.85%29.aspx says this is safe to do now - stops->Release(); - return brush; -} - -static ID2D1Brush *makeRadialBrush(uiDrawBrush *b, ID2D1RenderTarget *rt, D2D1_BRUSH_PROPERTIES *props) -{ - ID2D1RadialGradientBrush *brush; - D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES gprops; - ID2D1GradientStopCollection *stops; - HRESULT hr; - - ZeroMemory(&gprops, sizeof (D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES)); - gprops.gradientOriginOffset.x = b->X0 - b->X1; - gprops.gradientOriginOffset.y = b->Y0 - b->Y1; - gprops.center.x = b->X1; - gprops.center.y = b->Y1; - gprops.radiusX = b->OuterRadius; - gprops.radiusY = b->OuterRadius; - - stops = mkstops(b, rt); - - hr = rt->CreateRadialGradientBrush( - &gprops, - props, - stops, - &brush); - if (hr != S_OK) - logHRESULT(L"error creating gradient brush", hr); - - stops->Release(); - return brush; -} - -static ID2D1Brush *makeBrush(uiDrawBrush *b, ID2D1RenderTarget *rt) -{ - D2D1_BRUSH_PROPERTIES props; - - ZeroMemory(&props, sizeof (D2D1_BRUSH_PROPERTIES)); - props.opacity = 1.0; - // identity matrix - props.transform._11 = 1; - props.transform._22 = 1; - - switch (b->Type) { - case uiDrawBrushTypeSolid: - return makeSolidBrush(b, rt, &props); - case uiDrawBrushTypeLinearGradient: - return makeLinearBrush(b, rt, &props); - case uiDrawBrushTypeRadialGradient: - return makeRadialBrush(b, rt, &props); -// case uiDrawBrushTypeImage: -// TODO - } - - // TODO do this on all platforms - userbug("Invalid brush type %d given to drawing operation.", b->Type); - // TODO dummy brush? - return NULL; // make compiler happy -} - -// how clipping works: -// every fill and stroke is done on a temporary layer with the clip geometry applied to it -// this is really the only way to clip in Direct2D that doesn't involve opacity images -// reference counting: -// - initially the clip is NULL, which means do not use a layer -// - the first time uiDrawClip() is called, we take a reference on the path passed in (this is also why uiPathEnd() is needed) -// - every successive time, we create a new PathGeometry and merge the current clip with the new path, releasing the reference we took earlier and taking a reference to the new one -// - in Save, we take another reference; in Restore we drop the refernece to the existing path geometry and transfer that saved ref to the new path geometry over to the context -// uiDrawFreePath() doesn't destroy the path geometry, it just drops the reference count, so a clip can exist independent of its path - -static ID2D1Layer *applyClip(uiDrawContext *c) -{ - ID2D1Layer *layer; - D2D1_LAYER_PARAMETERS params; - HRESULT hr; - - // if no clip, don't do anything - if (c->currentClip == NULL) - return NULL; - - // create a layer for clipping - // we have to explicitly make the layer because we're still targeting Windows 7 - hr = c->rt->CreateLayer(NULL, &layer); - if (hr != S_OK) - logHRESULT(L"error creating clip layer", hr); - - // apply it as the clip - ZeroMemory(¶ms, sizeof (D2D1_LAYER_PARAMETERS)); - // this is the equivalent of InfiniteRect() in d2d1helper.h - params.contentBounds.left = -FLT_MAX; - params.contentBounds.top = -FLT_MAX; - params.contentBounds.right = FLT_MAX; - params.contentBounds.bottom = FLT_MAX; - params.geometricMask = (ID2D1Geometry *) (c->currentClip); - // TODO is this correct? - params.maskAntialiasMode = c->rt->GetAntialiasMode(); - // identity matrix - params.maskTransform._11 = 1; - params.maskTransform._22 = 1; - params.opacity = 1.0; - params.opacityBrush = NULL; - params.layerOptions = D2D1_LAYER_OPTIONS_NONE; - // TODO is this correct? - if (c->rt->GetTextAntialiasMode() == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE) - params.layerOptions = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE; - c->rt->PushLayer(¶ms, layer); - - // return the layer so it can be freed later - return layer; -} - -static void unapplyClip(uiDrawContext *c, ID2D1Layer *layer) -{ - if (layer == NULL) - return; - c->rt->PopLayer(); - layer->Release(); -} - -void uiDrawStroke(uiDrawContext *c, uiDrawPath *p, uiDrawBrush *b, uiDrawStrokeParams *sp) -{ - ID2D1Brush *brush; - ID2D1StrokeStyle *style; - D2D1_STROKE_STYLE_PROPERTIES dsp; - FLOAT *dashes; - size_t i; - ID2D1Layer *cliplayer; - HRESULT hr; - - brush = makeBrush(b, c->rt); - - ZeroMemory(&dsp, sizeof (D2D1_STROKE_STYLE_PROPERTIES)); - switch (sp->Cap) { - case uiDrawLineCapFlat: - dsp.startCap = D2D1_CAP_STYLE_FLAT; - dsp.endCap = D2D1_CAP_STYLE_FLAT; - dsp.dashCap = D2D1_CAP_STYLE_FLAT; - break; - case uiDrawLineCapRound: - dsp.startCap = D2D1_CAP_STYLE_ROUND; - dsp.endCap = D2D1_CAP_STYLE_ROUND; - dsp.dashCap = D2D1_CAP_STYLE_ROUND; - break; - case uiDrawLineCapSquare: - dsp.startCap = D2D1_CAP_STYLE_SQUARE; - dsp.endCap = D2D1_CAP_STYLE_SQUARE; - dsp.dashCap = D2D1_CAP_STYLE_SQUARE; - break; - } - switch (sp->Join) { - case uiDrawLineJoinMiter: - dsp.lineJoin = D2D1_LINE_JOIN_MITER_OR_BEVEL; - dsp.miterLimit = sp->MiterLimit; - break; - case uiDrawLineJoinRound: - dsp.lineJoin = D2D1_LINE_JOIN_ROUND; - break; - case uiDrawLineJoinBevel: - dsp.lineJoin = D2D1_LINE_JOIN_BEVEL; - break; - } - dsp.dashStyle = D2D1_DASH_STYLE_SOLID; - dashes = NULL; - // note that dash widths and the dash phase are scaled up by the thickness by Direct2D - // TODO be sure to formally document this - if (sp->NumDashes != 0) { - dsp.dashStyle = D2D1_DASH_STYLE_CUSTOM; - dashes = (FLOAT *) uiAlloc(sp->NumDashes * sizeof (FLOAT), "FLOAT[]"); - for (i = 0; i < sp->NumDashes; i++) - dashes[i] = sp->Dashes[i] / sp->Thickness; - } - dsp.dashOffset = sp->DashPhase / sp->Thickness; - hr = d2dfactory->CreateStrokeStyle( - &dsp, - dashes, - sp->NumDashes, - &style); - if (hr != S_OK) - logHRESULT(L"error creating stroke style", hr); - if (sp->NumDashes != 0) - uiFree(dashes); - - cliplayer = applyClip(c); - c->rt->DrawGeometry( - pathGeometry(p), - brush, - sp->Thickness, - style); - unapplyClip(c, cliplayer); - - style->Release(); - brush->Release(); -} - -void uiDrawFill(uiDrawContext *c, uiDrawPath *p, uiDrawBrush *b) -{ - ID2D1Brush *brush; - ID2D1Layer *cliplayer; - - brush = makeBrush(b, c->rt); - cliplayer = applyClip(c); - c->rt->FillGeometry( - pathGeometry(p), - brush, - NULL); - unapplyClip(c, cliplayer); - brush->Release(); -} - -void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m) -{ - D2D1_MATRIX_3X2_F dm, cur; - - c->rt->GetTransform(&cur); - m2d(m, &dm); - // you would think we have to do already * m, right? - // WRONG! we have to do m * already - // why? a few reasons - // a) this lovely comment in cairo's source - http://cgit.freedesktop.org/cairo/tree/src/cairo-matrix.c?id=0537479bd1d4c5a3bc0f6f41dec4deb98481f34a#n330 - // Direct2D uses column vectors and I don't know if this is even documented - // b) that's what Core Graphics does - // TODO see if Microsoft says to do this - dm = dm * cur; // for whatever reason operator * is defined but not operator *= - c->rt->SetTransform(&dm); -} - -void uiDrawClip(uiDrawContext *c, uiDrawPath *path) -{ - ID2D1PathGeometry *newPath; - ID2D1GeometrySink *newSink; - HRESULT hr; - - // if there's no current clip, borrow the path - if (c->currentClip == NULL) { - c->currentClip = pathGeometry(path); - // we have to take our own reference to that clip - c->currentClip->AddRef(); - return; - } - - // otherwise we have to intersect the current path with the new one - // we do that into a new path, and then replace c->currentClip with that new path - hr = d2dfactory->CreatePathGeometry(&newPath); - if (hr != S_OK) - logHRESULT(L"error creating new path", hr); - hr = newPath->Open(&newSink); - if (hr != S_OK) - logHRESULT(L"error opening new path", hr); - hr = c->currentClip->CombineWithGeometry( - pathGeometry(path), - D2D1_COMBINE_MODE_INTERSECT, - NULL, - // TODO is this correct or can this be set per target? - D2D1_DEFAULT_FLATTENING_TOLERANCE, - newSink); - if (hr != S_OK) - logHRESULT(L"error intersecting old path with new path", hr); - hr = newSink->Close(); - if (hr != S_OK) - logHRESULT(L"error closing new path", hr); - newSink->Release(); - - // okay we have the new clip; we just need to replace the old one with it - c->currentClip->Release(); - c->currentClip = newPath; - // we have a reference already; no need for another -} - -struct drawState { - ID2D1DrawingStateBlock *dsb; - ID2D1PathGeometry *clip; -}; - -void uiDrawSave(uiDrawContext *c) -{ - struct drawState state; - HRESULT hr; - - hr = d2dfactory->CreateDrawingStateBlock( - // TODO verify that these are correct - NULL, - NULL, - &(state.dsb)); - if (hr != S_OK) - logHRESULT(L"error creating drawing state block", hr); - c->rt->SaveDrawingState(state.dsb); - - // if we have a clip, we need to hold another reference to it - if (c->currentClip != NULL) - c->currentClip->AddRef(); - state.clip = c->currentClip; // even if NULL assign it - - c->states->push_back(state); -} - -void uiDrawRestore(uiDrawContext *c) -{ - struct drawState state; - - state = (*(c->states))[c->states->size() - 1]; - c->states->pop_back(); - - c->rt->RestoreDrawingState(state.dsb); - state.dsb->Release(); - - // if we have a current clip, we need to drop it - if (c->currentClip != NULL) - c->currentClip->Release(); - // no need to explicitly addref or release; just transfer the ref - c->currentClip = state.clip; -} diff --git a/deps/libui/windows/draw.hpp b/deps/libui/windows/draw.hpp deleted file mode 100644 index b015791fe9..0000000000 --- a/deps/libui/windows/draw.hpp +++ /dev/null @@ -1,16 +0,0 @@ -// 5 may 2016 - -// draw.cpp -extern ID2D1Factory *d2dfactory; -struct uiDrawContext { - ID2D1RenderTarget *rt; - // TODO find out how this works - std::vector *states; - ID2D1PathGeometry *currentClip; -}; - -// drawpath.cpp -extern ID2D1PathGeometry *pathGeometry(uiDrawPath *p); - -// drawmatrix.cpp -extern void m2d(uiDrawMatrix *m, D2D1_MATRIX_3X2_F *d); diff --git a/deps/libui/windows/drawmatrix.cpp b/deps/libui/windows/drawmatrix.cpp deleted file mode 100644 index 090972a558..0000000000 --- a/deps/libui/windows/drawmatrix.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// 7 september 2015 -#include "uipriv_windows.hpp" -#include "draw.hpp" - -void m2d(uiDrawMatrix *m, D2D1_MATRIX_3X2_F *d) -{ - d->_11 = m->M11; - d->_12 = m->M12; - d->_21 = m->M21; - d->_22 = m->M22; - d->_31 = m->M31; - d->_32 = m->M32; -} - -static void d2m(D2D1_MATRIX_3X2_F *d, uiDrawMatrix *m) -{ - m->M11 = d->_11; - m->M12 = d->_12; - m->M21 = d->_21; - m->M22 = d->_22; - m->M31 = d->_31; - m->M32 = d->_32; -} - -void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y) -{ - D2D1_MATRIX_3X2_F dm; - - m2d(m, &dm); - dm = dm * D2D1::Matrix3x2F::Translation(x, y); - d2m(&dm, m); -} - -void uiDrawMatrixScale(uiDrawMatrix *m, double xCenter, double yCenter, double x, double y) -{ - D2D1_MATRIX_3X2_F dm; - D2D1_POINT_2F center; - - m2d(m, &dm); - center.x = xCenter; - center.y = yCenter; - dm = dm * D2D1::Matrix3x2F::Scale(x, y, center); - d2m(&dm, m); -} - -#define r2d(x) (x * (180.0 / uiPi)) - -void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount) -{ - D2D1_MATRIX_3X2_F dm; - D2D1_POINT_2F center; - - m2d(m, &dm); - center.x = x; - center.y = y; - dm = dm * D2D1::Matrix3x2F::Rotation(r2d(amount), center); - d2m(&dm, m); -} - -void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount) -{ - D2D1_MATRIX_3X2_F dm; - D2D1_POINT_2F center; - - m2d(m, &dm); - center.x = x; - center.y = y; - dm = dm * D2D1::Matrix3x2F::Skew(r2d(xamount), r2d(yamount), center); - d2m(&dm, m); -} - -void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src) -{ - D2D1_MATRIX_3X2_F c, d; - - m2d(dest, &c); - m2d(src, &d); - c = c * d; - d2m(&c, dest); -} - -int uiDrawMatrixInvertible(uiDrawMatrix *m) -{ - D2D1_MATRIX_3X2_F d; - - m2d(m, &d); - return D2D1IsMatrixInvertible(&d) != FALSE; -} - -int uiDrawMatrixInvert(uiDrawMatrix *m) -{ - D2D1_MATRIX_3X2_F d; - - m2d(m, &d); - if (D2D1InvertMatrix(&d) == FALSE) - return 0; - d2m(&d, m); - return 1; -} - -void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y) -{ - D2D1::Matrix3x2F dm; - D2D1_POINT_2F pt; - - m2d(m, &dm); - pt.x = *x; - pt.y = *y; - pt = dm.TransformPoint(pt); - *x = pt.x; - *y = pt.y; -} - -void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y) -{ - fallbackTransformSize(m, x, y); -} diff --git a/deps/libui/windows/drawpath.cpp b/deps/libui/windows/drawpath.cpp deleted file mode 100644 index 49855be6c3..0000000000 --- a/deps/libui/windows/drawpath.cpp +++ /dev/null @@ -1,246 +0,0 @@ -// 7 september 2015 -#include "uipriv_windows.hpp" -#include "draw.hpp" - -// TODO -// - write a test for transform followed by clip and clip followed by transform to make sure they work the same as on gtk+ and cocoa -// - write a test for nested transforms for gtk+ - -struct uiDrawPath { - ID2D1PathGeometry *path; - ID2D1GeometrySink *sink; - BOOL inFigure; -}; - -uiDrawPath *uiDrawNewPath(uiDrawFillMode fillmode) -{ - uiDrawPath *p; - HRESULT hr; - - p = uiNew(uiDrawPath); - hr = d2dfactory->CreatePathGeometry(&(p->path)); - if (hr != S_OK) - logHRESULT(L"error creating path", hr); - hr = p->path->Open(&(p->sink)); - if (hr != S_OK) - logHRESULT(L"error opening path", hr); - switch (fillmode) { - case uiDrawFillModeWinding: - p->sink->SetFillMode(D2D1_FILL_MODE_WINDING); - break; - case uiDrawFillModeAlternate: - p->sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE); - break; - } - return p; -} - -void uiDrawFreePath(uiDrawPath *p) -{ - if (p->inFigure) - p->sink->EndFigure(D2D1_FIGURE_END_OPEN); - if (p->sink != NULL) - // TODO close sink first? - p->sink->Release(); - p->path->Release(); - uiFree(p); -} - -void uiDrawPathNewFigure(uiDrawPath *p, double x, double y) -{ - D2D1_POINT_2F pt; - - if (p->inFigure) - p->sink->EndFigure(D2D1_FIGURE_END_OPEN); - pt.x = x; - pt.y = y; - p->sink->BeginFigure(pt, D2D1_FIGURE_BEGIN_FILLED); - p->inFigure = TRUE; -} - -// Direct2D arcs require a little explanation. -// An arc in Direct2D is defined by the chord between the endpoints. -// There are four possible arcs with the same two endpoints that you can draw this way. -// See https://www.youtube.com/watch?v=ATS0ANW1UxQ for a demonstration. -// There is a property rotationAngle which deals with the rotation /of the entire ellipse that forms an ellpitical arc/ - it's effectively a transformation on the arc. -// That is to say, it's NOT THE SWEEP. -// The sweep is defined by the start and end points and whether the arc is "large". -// As a result, this design does not allow for full circles or ellipses with a single arc; they have to be simulated with two. - -struct arc { - double xCenter; - double yCenter; - double radius; - double startAngle; - double sweep; - int negative; -}; - -// this is used for the comparison below -// if it falls apart it can be changed later -#define aerMax 6 * DBL_EPSILON - -static void drawArc(uiDrawPath *p, struct arc *a, void (*startFunction)(uiDrawPath *, double, double)) -{ - double sinx, cosx; - double startX, startY; - double endX, endY; - D2D1_ARC_SEGMENT as; - BOOL fullCircle; - double absSweep; - - // as above, we can't do a full circle with one arc - // simulate it with two half-circles - // of course, we have a dragon: equality on floating-point values! - // I've chosen to do the AlmostEqualRelative() technique in https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ - fullCircle = FALSE; - // use the absolute value to tackle both ≥2π and ≤-2π at the same time - absSweep = fabs(a->sweep); - if (absSweep > (2 * uiPi)) // this part is easy - fullCircle = TRUE; - else { - double aerDiff; - - aerDiff = fabs(absSweep - (2 * uiPi)); - // if we got here then we know a->sweep is larger (or the same!) - fullCircle = aerDiff <= absSweep * aerMax; - } - // TODO make sure this works right for the negative direction - if (fullCircle) { - a->sweep = uiPi; - drawArc(p, a, startFunction); - a->startAngle += uiPi; - drawArc(p, a, NULL); - return; - } - - // first, figure out the arc's endpoints - // unfortunately D2D1SinCos() is only defined on Windows 8 and newer - // the MSDN page doesn't say this, but says it requires d2d1_1.h, which is listed as only supported on Windows 8 and newer elsewhere on MSDN - // so we must use sin() and cos() and hope it's right... - sinx = sin(a->startAngle); - cosx = cos(a->startAngle); - startX = a->xCenter + a->radius * cosx; - startY = a->yCenter + a->radius * sinx; - sinx = sin(a->startAngle + a->sweep); - cosx = cos(a->startAngle + a->sweep); - endX = a->xCenter + a->radius * cosx; - endY = a->yCenter + a->radius * sinx; - - // now do the initial step to get the current point to be the start point - // this is either creating a new figure, drawing a line, or (in the case of our full circle code above) doing nothing - if (startFunction != NULL) - (*startFunction)(p, startX, startY); - - // now we can draw the arc - as.point.x = endX; - as.point.y = endY; - as.size.width = a->radius; - as.size.height = a->radius; - as.rotationAngle = 0; // as above, not relevant for circles - if (a->negative) - as.sweepDirection = D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE; - else - as.sweepDirection = D2D1_SWEEP_DIRECTION_CLOCKWISE; - // TODO explain the outer if - if (!a->negative) - if (a->sweep > uiPi) - as.arcSize = D2D1_ARC_SIZE_LARGE; - else - as.arcSize = D2D1_ARC_SIZE_SMALL; - else - // TODO especially this part - if (a->sweep > uiPi) - as.arcSize = D2D1_ARC_SIZE_SMALL; - else - as.arcSize = D2D1_ARC_SIZE_LARGE; - p->sink->AddArc(&as); -} - -void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative) -{ - struct arc a; - - a.xCenter = xCenter; - a.yCenter = yCenter; - a.radius = radius; - a.startAngle = startAngle; - a.sweep = sweep; - a.negative = negative; - drawArc(p, &a, uiDrawPathNewFigure); -} - -void uiDrawPathLineTo(uiDrawPath *p, double x, double y) -{ - D2D1_POINT_2F pt; - - pt.x = x; - pt.y = y; - p->sink->AddLine(pt); -} - -void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative) -{ - struct arc a; - - a.xCenter = xCenter; - a.yCenter = yCenter; - a.radius = radius; - a.startAngle = startAngle; - a.sweep = sweep; - a.negative = negative; - drawArc(p, &a, uiDrawPathLineTo); -} - -void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY) -{ - D2D1_BEZIER_SEGMENT s; - - s.point1.x = c1x; - s.point1.y = c1y; - s.point2.x = c2x; - s.point2.y = c2y; - s.point3.x = endX; - s.point3.y = endY; - p->sink->AddBezier(&s); -} - -void uiDrawPathCloseFigure(uiDrawPath *p) -{ - p->sink->EndFigure(D2D1_FIGURE_END_CLOSED); - p->inFigure = FALSE; -} - -void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height) -{ - // this is the same algorithm used by cairo and Core Graphics, according to their documentations - uiDrawPathNewFigure(p, x, y); - uiDrawPathLineTo(p, x + width, y); - uiDrawPathLineTo(p, x + width, y + height); - uiDrawPathLineTo(p, x, y + height); - uiDrawPathCloseFigure(p); -} - -void uiDrawPathEnd(uiDrawPath *p) -{ - HRESULT hr; - - if (p->inFigure) { - p->sink->EndFigure(D2D1_FIGURE_END_OPEN); - // needed for uiDrawFreePath() - p->inFigure = FALSE; - } - hr = p->sink->Close(); - if (hr != S_OK) - logHRESULT(L"error closing path", hr); - p->sink->Release(); - // also needed for uiDrawFreePath() - p->sink = NULL; -} - -ID2D1PathGeometry *pathGeometry(uiDrawPath *p) -{ - if (p->sink != NULL) - userbug("You cannot draw with a uiDrawPath that was not ended. (path: %p)", p); - return p->path; -} diff --git a/deps/libui/windows/drawtext.cpp b/deps/libui/windows/drawtext.cpp deleted file mode 100644 index 05a24f6776..0000000000 --- a/deps/libui/windows/drawtext.cpp +++ /dev/null @@ -1,531 +0,0 @@ -// 22 december 2015 -#include "uipriv_windows.hpp" -#include "draw.hpp" -// TODO really migrate - -// notes: -// only available in windows 8 and newer: -// - character spacing -// - kerning control -// - justficiation (how could I possibly be making this up?!) -// - vertical text (SERIOUSLY?! WHAT THE ACTUAL FUCK, MICROSOFT?!?!?!? DID YOU NOT THINK ABOUT THIS THE FIRST TIME, TRYING TO IMPROVE THE INTERNATIONALIZATION OF WINDOWS 7?!?!?! bonus: some parts of MSDN even say 8.1 and up only!) - -struct uiDrawFontFamilies { - fontCollection *fc; -}; - -uiDrawFontFamilies *uiDrawListFontFamilies(void) -{ - struct uiDrawFontFamilies *ff; - - ff = uiNew(struct uiDrawFontFamilies); - ff->fc = loadFontCollection(); - return ff; -} - -int uiDrawFontFamiliesNumFamilies(uiDrawFontFamilies *ff) -{ - return ff->fc->fonts->GetFontFamilyCount(); -} - -char *uiDrawFontFamiliesFamily(uiDrawFontFamilies *ff, int n) -{ - IDWriteFontFamily *family; - WCHAR *wname; - char *name; - HRESULT hr; - - hr = ff->fc->fonts->GetFontFamily(n, &family); - if (hr != S_OK) - logHRESULT(L"error getting font out of collection", hr); - wname = fontCollectionFamilyName(ff->fc, family); - name = toUTF8(wname); - uiFree(wname); - family->Release(); - return name; -} - -void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff) -{ - fontCollectionFree(ff->fc); - uiFree(ff); -} - -struct uiDrawTextFont { - IDWriteFont *f; - WCHAR *family; // save for convenience in uiDrawNewTextLayout() - double size; -}; - -uiDrawTextFont *mkTextFont(IDWriteFont *df, BOOL addRef, WCHAR *family, BOOL copyFamily, double size) -{ - uiDrawTextFont *font; - WCHAR *copy; - HRESULT hr; - - font = uiNew(uiDrawTextFont); - font->f = df; - if (addRef) - font->f->AddRef(); - if (copyFamily) { - copy = (WCHAR *) uiAlloc((wcslen(family) + 1) * sizeof (WCHAR), "WCHAR[]"); - wcscpy(copy, family); - font->family = copy; - } else - font->family = family; - font->size = size; - return font; -} - -// TODO consider moving these all to dwrite.cpp - -// TODO MinGW-w64 is missing this one -#define DWRITE_FONT_WEIGHT_SEMI_LIGHT (DWRITE_FONT_WEIGHT(350)) -static const struct { - bool lastOne; - uiDrawTextWeight uival; - DWRITE_FONT_WEIGHT dwval; -} dwriteWeights[] = { - { false, uiDrawTextWeightThin, DWRITE_FONT_WEIGHT_THIN }, - { false, uiDrawTextWeightUltraLight, DWRITE_FONT_WEIGHT_ULTRA_LIGHT }, - { false, uiDrawTextWeightLight, DWRITE_FONT_WEIGHT_LIGHT }, - { false, uiDrawTextWeightBook, DWRITE_FONT_WEIGHT_SEMI_LIGHT }, - { false, uiDrawTextWeightNormal, DWRITE_FONT_WEIGHT_NORMAL }, - { false, uiDrawTextWeightMedium, DWRITE_FONT_WEIGHT_MEDIUM }, - { false, uiDrawTextWeightSemiBold, DWRITE_FONT_WEIGHT_SEMI_BOLD }, - { false, uiDrawTextWeightBold, DWRITE_FONT_WEIGHT_BOLD }, - { false, uiDrawTextWeightUltraBold, DWRITE_FONT_WEIGHT_ULTRA_BOLD }, - { false, uiDrawTextWeightHeavy, DWRITE_FONT_WEIGHT_HEAVY }, - { true, uiDrawTextWeightUltraHeavy, DWRITE_FONT_WEIGHT_ULTRA_BLACK, }, -}; - -static const struct { - bool lastOne; - uiDrawTextItalic uival; - DWRITE_FONT_STYLE dwval; -} dwriteItalics[] = { - { false, uiDrawTextItalicNormal, DWRITE_FONT_STYLE_NORMAL }, - { false, uiDrawTextItalicOblique, DWRITE_FONT_STYLE_OBLIQUE }, - { true, uiDrawTextItalicItalic, DWRITE_FONT_STYLE_ITALIC }, -}; - -static const struct { - bool lastOne; - uiDrawTextStretch uival; - DWRITE_FONT_STRETCH dwval; -} dwriteStretches[] = { - { false, uiDrawTextStretchUltraCondensed, DWRITE_FONT_STRETCH_ULTRA_CONDENSED }, - { false, uiDrawTextStretchExtraCondensed, DWRITE_FONT_STRETCH_EXTRA_CONDENSED }, - { false, uiDrawTextStretchCondensed, DWRITE_FONT_STRETCH_CONDENSED }, - { false, uiDrawTextStretchSemiCondensed, DWRITE_FONT_STRETCH_SEMI_CONDENSED }, - { false, uiDrawTextStretchNormal, DWRITE_FONT_STRETCH_NORMAL }, - { false, uiDrawTextStretchSemiExpanded, DWRITE_FONT_STRETCH_SEMI_EXPANDED }, - { false, uiDrawTextStretchExpanded, DWRITE_FONT_STRETCH_EXPANDED }, - { false, uiDrawTextStretchExtraExpanded, DWRITE_FONT_STRETCH_EXTRA_EXPANDED }, - { true, uiDrawTextStretchUltraExpanded, DWRITE_FONT_STRETCH_ULTRA_EXPANDED }, -}; - -void attrToDWriteAttr(struct dwriteAttr *attr) -{ - bool found; - int i; - - found = false; - for (i = 0; ; i++) { - if (dwriteWeights[i].uival == attr->weight) { - attr->dweight = dwriteWeights[i].dwval; - found = true; - break; - } - if (dwriteWeights[i].lastOne) - break; - } - if (!found) - userbug("Invalid text weight %d passed to text function.", attr->weight); - - found = false; - for (i = 0; ; i++) { - if (dwriteItalics[i].uival == attr->italic) { - attr->ditalic = dwriteItalics[i].dwval; - found = true; - break; - } - if (dwriteItalics[i].lastOne) - break; - } - if (!found) - userbug("Invalid text italic %d passed to text function.", attr->italic); - - found = false; - for (i = 0; ; i++) { - if (dwriteStretches[i].uival == attr->stretch) { - attr->dstretch = dwriteStretches[i].dwval; - found = true; - break; - } - if (dwriteStretches[i].lastOne) - break; - } - if (!found) - // TODO on other platforms too - userbug("Invalid text stretch %d passed to text function.", attr->stretch); -} - -void dwriteAttrToAttr(struct dwriteAttr *attr) -{ - int weight, against, n; - int curdiff, curindex; - bool found; - int i; - - // weight is scaled; we need to test to see what's nearest - weight = (int) (attr->dweight); - against = (int) (dwriteWeights[0].dwval); - curdiff = abs(against - weight); - curindex = 0; - for (i = 1; ; i++) { - against = (int) (dwriteWeights[i].dwval); - n = abs(against - weight); - if (n < curdiff) { - curdiff = n; - curindex = i; - } - if (dwriteWeights[i].lastOne) - break; - } - attr->weight = dwriteWeights[i].uival; - - // italic and stretch are simple values; we can just do a matching search - found = false; - for (i = 0; ; i++) { - if (dwriteItalics[i].dwval == attr->ditalic) { - attr->italic = dwriteItalics[i].uival; - found = true; - break; - } - if (dwriteItalics[i].lastOne) - break; - } - if (!found) - // these are implbug()s because users shouldn't be able to get here directly; TODO? - implbug("invalid italic %d passed to dwriteAttrToAttr()", attr->ditalic); - - found = false; - for (i = 0; ; i++) { - if (dwriteStretches[i].dwval == attr->dstretch) { - attr->stretch = dwriteStretches[i].uival; - found = true; - break; - } - if (dwriteStretches[i].lastOne) - break; - } - if (!found) - implbug("invalid stretch %d passed to dwriteAttrToAttr()", attr->dstretch); -} - -uiDrawTextFont *uiDrawLoadClosestFont(const uiDrawTextFontDescriptor *desc) -{ - uiDrawTextFont *font; - IDWriteFontCollection *collection; - UINT32 index; - BOOL exists; - struct dwriteAttr attr; - IDWriteFontFamily *family; - WCHAR *wfamily; - IDWriteFont *match; - HRESULT hr; - - // always get the latest available font information - hr = dwfactory->GetSystemFontCollection(&collection, TRUE); - if (hr != S_OK) - logHRESULT(L"error getting system font collection", hr); - - wfamily = toUTF16(desc->Family); - hr = collection->FindFamilyName(wfamily, &index, &exists); - if (hr != S_OK) - logHRESULT(L"error finding font family", hr); - if (!exists) - implbug("LONGTERM family not found in uiDrawLoadClosestFont()", hr); - hr = collection->GetFontFamily(index, &family); - if (hr != S_OK) - logHRESULT(L"error loading font family", hr); - - attr.weight = desc->Weight; - attr.italic = desc->Italic; - attr.stretch = desc->Stretch; - attrToDWriteAttr(&attr); - hr = family->GetFirstMatchingFont( - attr.dweight, - attr.dstretch, - attr.ditalic, - &match); - if (hr != S_OK) - logHRESULT(L"error loading font", hr); - - font = mkTextFont(match, - FALSE, // we own the initial reference; no need to add another one - wfamily, FALSE, // will be freed with font - desc->Size); - - family->Release(); - collection->Release(); - - return font; -} - -void uiDrawFreeTextFont(uiDrawTextFont *font) -{ - font->f->Release(); - uiFree(font->family); - uiFree(font); -} - -uintptr_t uiDrawTextFontHandle(uiDrawTextFont *font) -{ - return (uintptr_t) (font->f); -} - -void uiDrawTextFontDescribe(uiDrawTextFont *font, uiDrawTextFontDescriptor *desc) -{ - // TODO - - desc->Size = font->size; - - // TODO -} - -// text sizes are 1/72 of an inch -// points in Direct2D are 1/96 of an inch (https://msdn.microsoft.com/en-us/library/windows/desktop/ff684173%28v=vs.85%29.aspx, https://msdn.microsoft.com/en-us/library/windows/desktop/hh447022%28v=vs.85%29.aspx) -// As for the actual conversion from design units, see: -// - http://cboard.cprogramming.com/windows-programming/136733-directwrite-font-height-issues.html -// - https://sourceforge.net/p/vstgui/mailman/message/32483143/ -// - http://xboxforums.create.msdn.com/forums/t/109445.aspx -// - https://msdn.microsoft.com/en-us/library/dd183564%28v=vs.85%29.aspx -// - http://www.fontbureau.com/blog/the-em/ -// TODO make points here about how DIPs in DirectWrite == DIPs in Direct2D; if not, figure out what they really are? for the width and layout functions later -static double scaleUnits(double what, double designUnitsPerEm, double size) -{ - return (what / designUnitsPerEm) * (size * (96.0 / 72.0)); -} - -void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metrics) -{ - DWRITE_FONT_METRICS dm; - - font->f->GetMetrics(&dm); - metrics->Ascent = scaleUnits(dm.ascent, dm.designUnitsPerEm, font->size); - metrics->Descent = scaleUnits(dm.descent, dm.designUnitsPerEm, font->size); - // TODO what happens if dm.xxx is negative? - // TODO remember what this was for - metrics->Leading = scaleUnits(dm.lineGap, dm.designUnitsPerEm, font->size); - metrics->UnderlinePos = scaleUnits(dm.underlinePosition, dm.designUnitsPerEm, font->size); - metrics->UnderlineThickness = scaleUnits(dm.underlineThickness, dm.designUnitsPerEm, font->size); -} - -// some attributes, such as foreground color, can't be applied until after we establish a Direct2D context :/ so we have to prepare all attributes in advance -// also since there's no way to clear the attributes from a layout en masse (apart from overwriting them all), we'll play it safe by creating a new layout each time -enum layoutAttrType { - layoutAttrColor, -}; - -struct layoutAttr { - enum layoutAttrType type; - int start; - int end; - double components[4]; -}; - -struct uiDrawTextLayout { - WCHAR *text; - size_t textlen; - size_t *graphemes; - double width; - IDWriteTextFormat *format; - std::vector *attrs; -}; - -uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultFont, double width) -{ - uiDrawTextLayout *layout; - HRESULT hr; - - layout = uiNew(uiDrawTextLayout); - - hr = dwfactory->CreateTextFormat(defaultFont->family, - NULL, - defaultFont->f->GetWeight(), - defaultFont->f->GetStyle(), - defaultFont->f->GetStretch(), - // typographic points are 1/72 inch; this parameter is 1/96 inch - // fortunately Microsoft does this too, in https://msdn.microsoft.com/en-us/library/windows/desktop/dd371554%28v=vs.85%29.aspx - defaultFont->size * (96.0 / 72.0), - // see http://stackoverflow.com/questions/28397971/idwritefactorycreatetextformat-failing and https://msdn.microsoft.com/en-us/library/windows/desktop/dd368203.aspx - // TODO use the current locale again? - L"", - &(layout->format)); - if (hr != S_OK) - logHRESULT(L"error creating IDWriteTextFormat", hr); - - layout->text = toUTF16(text); - layout->textlen = wcslen(layout->text); - layout->graphemes = graphemes(layout->text); - - uiDrawTextLayoutSetWidth(layout, width); - - layout->attrs = new std::vector; - - return layout; -} - -void uiDrawFreeTextLayout(uiDrawTextLayout *layout) -{ - delete layout->attrs; - layout->format->Release(); - uiFree(layout->graphemes); - uiFree(layout->text); - uiFree(layout); -} - -static ID2D1SolidColorBrush *mkSolidBrush(ID2D1RenderTarget *rt, double r, double g, double b, double a) -{ - D2D1_BRUSH_PROPERTIES props; - D2D1_COLOR_F color; - ID2D1SolidColorBrush *brush; - HRESULT hr; - - ZeroMemory(&props, sizeof (D2D1_BRUSH_PROPERTIES)); - props.opacity = 1.0; - // identity matrix - props.transform._11 = 1; - props.transform._22 = 1; - color.r = r; - color.g = g; - color.b = b; - color.a = a; - hr = rt->CreateSolidColorBrush( - &color, - &props, - &brush); - if (hr != S_OK) - logHRESULT(L"error creating solid brush", hr); - return brush; -} - -IDWriteTextLayout *prepareLayout(uiDrawTextLayout *layout, ID2D1RenderTarget *rt) -{ - IDWriteTextLayout *dl; - DWRITE_TEXT_RANGE range; - IUnknown *unkBrush; - DWRITE_WORD_WRAPPING wrap; - FLOAT maxWidth; - HRESULT hr; - - hr = dwfactory->CreateTextLayout(layout->text, layout->textlen, - layout->format, - // FLOAT is float, not double, so this should work... TODO - FLT_MAX, FLT_MAX, - &dl); - if (hr != S_OK) - logHRESULT(L"error creating IDWriteTextLayout", hr); - - for (const struct layoutAttr &attr : *(layout->attrs)) { - range.startPosition = layout->graphemes[attr.start]; - range.length = layout->graphemes[attr.end] - layout->graphemes[attr.start]; - switch (attr.type) { - case layoutAttrColor: - if (rt == NULL) // determining extents, not drawing - break; - unkBrush = mkSolidBrush(rt, - attr.components[0], - attr.components[1], - attr.components[2], - attr.components[3]); - hr = dl->SetDrawingEffect(unkBrush, range); - unkBrush->Release(); // associated with dl - break; - default: - hr = E_FAIL; - logHRESULT(L"invalid text attribute type", hr); - } - if (hr != S_OK) - logHRESULT(L"error adding attribute to text layout", hr); - } - - // and set the width - // this is the only wrapping mode (apart from "no wrap") available prior to Windows 8.1 - wrap = DWRITE_WORD_WRAPPING_WRAP; - maxWidth = layout->width; - if (layout->width < 0) { - wrap = DWRITE_WORD_WRAPPING_NO_WRAP; - // setting the max width in this case technically isn't needed since the wrap mode will simply ignore the max width, but let's do it just to be safe - maxWidth = FLT_MAX; // see TODO above - } - hr = dl->SetWordWrapping(wrap); - if (hr != S_OK) - logHRESULT(L"error setting word wrapping mode", hr); - hr = dl->SetMaxWidth(maxWidth); - if (hr != S_OK) - logHRESULT(L"error setting max layout width", hr); - - return dl; -} - - -void uiDrawTextLayoutSetWidth(uiDrawTextLayout *layout, double width) -{ - layout->width = width; -} - -// TODO for a single line the height includes the leading; it should not -void uiDrawTextLayoutExtents(uiDrawTextLayout *layout, double *width, double *height) -{ - IDWriteTextLayout *dl; - DWRITE_TEXT_METRICS metrics; - HRESULT hr; - - dl = prepareLayout(layout, NULL); - hr = dl->GetMetrics(&metrics); - if (hr != S_OK) - logHRESULT(L"error getting layout metrics", hr); - *width = metrics.width; - // TODO make sure the behavior of this on empty strings is the same on all platforms - *height = metrics.height; - dl->Release(); -} - -void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout) -{ - IDWriteTextLayout *dl; - D2D1_POINT_2F pt; - ID2D1Brush *black; - HRESULT hr; - - // TODO document that fully opaque black is the default text color; figure out whether this is upheld in various scenarios on other platforms - black = mkSolidBrush(c->rt, 0.0, 0.0, 0.0, 1.0); - - dl = prepareLayout(layout, c->rt); - pt.x = x; - pt.y = y; - // TODO D2D1_DRAW_TEXT_OPTIONS_NO_SNAP? - // TODO D2D1_DRAW_TEXT_OPTIONS_CLIP? - // TODO when setting 8.1 as minimum, D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT? - c->rt->DrawTextLayout(pt, dl, black, D2D1_DRAW_TEXT_OPTIONS_NONE); - dl->Release(); - - black->Release(); -} - -void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endChar, double r, double g, double b, double a) -{ - struct layoutAttr attr; - - attr.type = layoutAttrColor; - attr.start = startChar; - attr.end = endChar; - attr.components[0] = r; - attr.components[1] = g; - attr.components[2] = b; - attr.components[3] = a; - layout->attrs->push_back(attr); -} diff --git a/deps/libui/windows/dwrite.cpp b/deps/libui/windows/dwrite.cpp deleted file mode 100644 index 9156f179d6..0000000000 --- a/deps/libui/windows/dwrite.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// 14 april 2016 -#include "uipriv_windows.hpp" -// TODO really migrate? - -IDWriteFactory *dwfactory = NULL; - -HRESULT initDrawText(void) -{ - // TOOD use DWRITE_FACTORY_TYPE_ISOLATED instead? - return DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, - __uuidof (IDWriteFactory), - (IUnknown **) (&dwfactory)); -} - -void uninitDrawText(void) -{ - dwfactory->Release(); -} - -fontCollection *loadFontCollection(void) -{ - fontCollection *fc; - HRESULT hr; - - fc = uiNew(fontCollection); - // always get the latest available font information - hr = dwfactory->GetSystemFontCollection(&(fc->fonts), TRUE); - if (hr != S_OK) - logHRESULT(L"error getting system font collection", hr); - fc->userLocaleSuccess = GetUserDefaultLocaleName(fc->userLocale, LOCALE_NAME_MAX_LENGTH); - return fc; -} - -WCHAR *fontCollectionFamilyName(fontCollection *fc, IDWriteFontFamily *family) -{ - IDWriteLocalizedStrings *names; - WCHAR *str; - HRESULT hr; - - hr = family->GetFamilyNames(&names); - if (hr != S_OK) - logHRESULT(L"error getting names of font out", hr); - str = fontCollectionCorrectString(fc, names); - names->Release(); - return str; -} - -WCHAR *fontCollectionCorrectString(fontCollection *fc, IDWriteLocalizedStrings *names) -{ - UINT32 index; - BOOL exists; - UINT32 length; - WCHAR *wname; - HRESULT hr; - - // this is complex, but we ignore failure conditions to allow fallbacks - // 1) If the user locale name was successfully retrieved, try it - // 2) If the user locale name was not successfully retrieved, or that locale's string does not exist, or an error occurred, try L"en-us", the US English locale - // 3) And if that fails, assume the first one - // This algorithm is straight from MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/dd368214%28v=vs.85%29.aspx - // For step 2 to work, start by setting hr to S_OK and exists to FALSE. - // TODO does it skip step 2 entirely if step 1 fails? rewrite it to be a more pure conversion of the MSDN code? - hr = S_OK; - exists = FALSE; - if (fc->userLocaleSuccess != 0) - hr = names->FindLocaleName(fc->userLocale, &index, &exists); - if (hr != S_OK || (hr == S_OK && !exists)) - hr = names->FindLocaleName(L"en-us", &index, &exists); - if (!exists) - index = 0; - - hr = names->GetStringLength(index, &length); - if (hr != S_OK) - logHRESULT(L"error getting length of font name", hr); - // GetStringLength() does not include the null terminator, but GetString() does - wname = (WCHAR *) uiAlloc((length + 1) * sizeof (WCHAR), "WCHAR[]"); - hr = names->GetString(index, wname, length + 1); - if (hr != S_OK) - logHRESULT(L"error getting font name", hr); - - return wname; -} - -void fontCollectionFree(fontCollection *fc) -{ - fc->fonts->Release(); - uiFree(fc); -} diff --git a/deps/libui/windows/editablecombo.cpp b/deps/libui/windows/editablecombo.cpp deleted file mode 100644 index 9e1fdbfbc3..0000000000 --- a/deps/libui/windows/editablecombo.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// 20 may 2015 -#include "uipriv_windows.hpp" - -// we as Common Controls 6 users don't need to worry about the height of comboboxes; see http://blogs.msdn.com/b/oldnewthing/archive/2006/03/10/548537.aspx - -struct uiEditableCombobox { - uiWindowsControl c; - HWND hwnd; - void (*onChanged)(uiEditableCombobox *, void *); - void *onChangedData; -}; - -static BOOL onWM_COMMAND(uiControl *cc, HWND hwnd, WORD code, LRESULT *lResult) -{ - uiEditableCombobox *c = uiEditableCombobox(cc); - - if (code == CBN_SELCHANGE) { - // like on OS X, this is sent before the edit has been updated :( - if (PostMessage(parentOf(hwnd), - WM_COMMAND, - MAKEWPARAM(GetWindowLongPtrW(hwnd, GWLP_ID), CBN_EDITCHANGE), - (LPARAM) hwnd) == 0) - logLastError(L"error posting CBN_EDITCHANGE after CBN_SELCHANGE"); - *lResult = 0; - return TRUE; - } - if (code != CBN_EDITCHANGE) - return FALSE; - (*(c->onChanged))(c, c->onChangedData); - *lResult = 0; - return TRUE; -} - -void uiEditableComboboxDestroy(uiControl *cc) -{ - uiEditableCombobox *c = uiEditableCombobox(cc); - - uiWindowsUnregisterWM_COMMANDHandler(c->hwnd); - uiWindowsEnsureDestroyWindow(c->hwnd); - uiFreeControl(uiControl(c)); -} - -uiWindowsControlAllDefaultsExceptDestroy(uiEditableCombobox) - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define comboboxWidth 107 /* this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary; LONGTERM */ -#define comboboxHeight 14 /* LONGTERM: is this too high? */ - -static void uiEditableComboboxMinimumSize(uiWindowsControl *cc, int *width, int *height) -{ - uiEditableCombobox *c = uiEditableCombobox(cc); - uiWindowsSizing sizing; - int x, y; - - x = comboboxWidth; - y = comboboxHeight; - uiWindowsGetSizing(c->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - *width = x; - *height = y; -} - -static void defaultOnChanged(uiEditableCombobox *c, void *data) -{ - // do nothing -} - -void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text) -{ - WCHAR *wtext; - LRESULT res; - - wtext = toUTF16(text); - res = SendMessageW(c->hwnd, CB_ADDSTRING, 0, (LPARAM) wtext); - if (res == (LRESULT) CB_ERR) - logLastError(L"error appending item to uiEditableCombobox"); - else if (res == (LRESULT) CB_ERRSPACE) - logLastError(L"memory exhausted appending item to uiEditableCombobox"); - uiFree(wtext); -} - -char *uiEditableComboboxText(uiEditableCombobox *c) -{ - return uiWindowsWindowText(c->hwnd); -} - -void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text) -{ - // does not trigger any notifications - uiWindowsSetWindowText(c->hwnd, text); -} - -void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data) -{ - c->onChanged = f; - c->onChangedData = data; -} - -uiEditableCombobox *uiNewEditableCombobox(void) -{ - uiEditableCombobox *c; - - uiWindowsNewControl(uiEditableCombobox, c); - - c->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE, - L"combobox", L"", - CBS_DROPDOWN | WS_TABSTOP, - hInstance, NULL, - TRUE); - - uiWindowsRegisterWM_COMMANDHandler(c->hwnd, onWM_COMMAND, uiControl(c)); - uiEditableComboboxOnChanged(c, defaultOnChanged, NULL); - - return c; -} diff --git a/deps/libui/windows/entry.cpp b/deps/libui/windows/entry.cpp deleted file mode 100644 index a7a077f203..0000000000 --- a/deps/libui/windows/entry.cpp +++ /dev/null @@ -1,134 +0,0 @@ -// 8 april 2015 -#include "uipriv_windows.hpp" - -struct uiEntry { - uiWindowsControl c; - HWND hwnd; - void (*onChanged)(uiEntry *, void *); - void *onChangedData; - BOOL inhibitChanged; -}; - -static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult) -{ - uiEntry *e = uiEntry(c); - - if (code != EN_CHANGE) - return FALSE; - if (e->inhibitChanged) - return FALSE; - (*(e->onChanged))(e, e->onChangedData); - *lResult = 0; - return TRUE; -} - -static void uiEntryDestroy(uiControl *c) -{ - uiEntry *e = uiEntry(c); - - uiWindowsUnregisterWM_COMMANDHandler(e->hwnd); - uiWindowsEnsureDestroyWindow(e->hwnd); - uiFreeControl(uiControl(e)); -} - -uiWindowsControlAllDefaultsExceptDestroy(uiEntry) - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define entryWidth 107 /* this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary */ -#define entryHeight 14 - -static void uiEntryMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiEntry *e = uiEntry(c); - uiWindowsSizing sizing; - int x, y; - - x = entryWidth; - y = entryHeight; - uiWindowsGetSizing(e->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - *width = x; - *height = y; -} - -static void defaultOnChanged(uiEntry *e, void *data) -{ - // do nothing -} - -char *uiEntryText(uiEntry *e) -{ - return uiWindowsWindowText(e->hwnd); -} - -void uiEntrySetText(uiEntry *e, const char *text) -{ - // doing this raises an EN_CHANGED - e->inhibitChanged = TRUE; - uiWindowsSetWindowText(e->hwnd, text); - e->inhibitChanged = FALSE; - // don't queue the control for resize; entry sizes are independent of their contents -} - -void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *, void *), void *data) -{ - e->onChanged = f; - e->onChangedData = data; -} - -int uiEntryReadOnly(uiEntry *e) -{ - return (getStyle(e->hwnd) & ES_READONLY) != 0; -} - -void uiEntrySetReadOnly(uiEntry *e, int readonly) -{ - WPARAM ro; - - ro = (WPARAM) FALSE; - if (readonly) - ro = (WPARAM) TRUE; - if (SendMessage(e->hwnd, EM_SETREADONLY, ro, 0) == 0) - logLastError(L"error making uiEntry read-only"); -} - -static uiEntry *finishNewEntry(DWORD style) -{ - uiEntry *e; - - uiWindowsNewControl(uiEntry, e); - - e->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE, - L"edit", L"", - style | ES_AUTOHSCROLL | ES_LEFT | ES_NOHIDESEL | WS_TABSTOP, - hInstance, NULL, - TRUE); - - uiWindowsRegisterWM_COMMANDHandler(e->hwnd, onWM_COMMAND, uiControl(e)); - uiEntryOnChanged(e, defaultOnChanged, NULL); - - return e; -} - -uiEntry *uiNewEntry(void) -{ - return finishNewEntry(0); -} - -uiEntry *uiNewPasswordEntry(void) -{ - return finishNewEntry(ES_PASSWORD); -} - -uiEntry *uiNewSearchEntry(void) -{ - uiEntry *e; - HRESULT hr; - - e = finishNewEntry(0); - // TODO this is from ThemeExplorer; is it documented anywhere? - // TODO SearchBoxEditComposited has no border - hr = SetWindowTheme(e->hwnd, L"SearchBoxEdit", NULL); - // TODO will hr be S_OK if themes are disabled? - return e; -} diff --git a/deps/libui/windows/events.cpp b/deps/libui/windows/events.cpp deleted file mode 100644 index 45e8d43d97..0000000000 --- a/deps/libui/windows/events.cpp +++ /dev/null @@ -1,151 +0,0 @@ -// 20 may 2015 -#include "uipriv_windows.hpp" - -struct handler { - BOOL (*commandHandler)(uiControl *, HWND, WORD, LRESULT *); - BOOL (*notifyHandler)(uiControl *, HWND, NMHDR *, LRESULT *); - BOOL (*hscrollHandler)(uiControl *, HWND, WORD, LRESULT *); - uiControl *c; - - // just to ensure handlers[new HWND] initializes properly - // TODO gcc can't handle a struct keyword here? or is that a MSVC extension? - handler() - { - this->commandHandler = NULL; - this->notifyHandler = NULL; - this->hscrollHandler = NULL; - this->c = NULL; - } -}; - -static std::map handlers; - -void uiWindowsRegisterWM_COMMANDHandler(HWND hwnd, BOOL (*handler)(uiControl *, HWND, WORD, LRESULT *), uiControl *c) -{ - if (handlers[hwnd].commandHandler != NULL) - implbug("already registered a WM_COMMAND handler to window handle %p", hwnd); - handlers[hwnd].commandHandler = handler; - handlers[hwnd].c = c; -} - -void uiWindowsRegisterWM_NOTIFYHandler(HWND hwnd, BOOL (*handler)(uiControl *, HWND, NMHDR *, LRESULT *), uiControl *c) -{ - if (handlers[hwnd].notifyHandler != NULL) - implbug("already registered a WM_NOTIFY handler to window handle %p", hwnd); - handlers[hwnd].notifyHandler = handler; - handlers[hwnd].c = c; -} - -void uiWindowsRegisterWM_HSCROLLHandler(HWND hwnd, BOOL (*handler)(uiControl *, HWND, WORD, LRESULT *), uiControl *c) -{ - if (handlers[hwnd].hscrollHandler != NULL) - implbug("already registered a WM_HSCROLL handler to window handle %p", hwnd); - handlers[hwnd].hscrollHandler = handler; - handlers[hwnd].c = c; -} - -void uiWindowsUnregisterWM_COMMANDHandler(HWND hwnd) -{ - if (handlers[hwnd].commandHandler == NULL) - implbug("window handle %p not registered to receive WM_COMMAND events", hwnd); - handlers[hwnd].commandHandler = NULL; -} - -void uiWindowsUnregisterWM_NOTIFYHandler(HWND hwnd) -{ - if (handlers[hwnd].notifyHandler == NULL) - implbug("window handle %p not registered to receive WM_NOTIFY events", hwnd); - handlers[hwnd].notifyHandler = NULL; -} - -void uiWindowsUnregisterWM_HSCROLLHandler(HWND hwnd) -{ - if (handlers[hwnd].hscrollHandler == NULL) - implbug("window handle %p not registered to receive WM_HSCROLL events", hwnd); - handlers[hwnd].hscrollHandler = NULL; -} - -template -static BOOL shouldRun(HWND hwnd, T method) -{ - // not from a window - if (hwnd == NULL) - return FALSE; - // don't bounce back if to the utility window, in which case act as if the message was ignored - if (IsChild(utilWindow, hwnd) != 0) - return FALSE; - // registered? - return method != NULL; -} - -BOOL runWM_COMMAND(WPARAM wParam, LPARAM lParam, LRESULT *lResult) -{ - HWND hwnd; - WORD arg3; - BOOL (*handler)(uiControl *, HWND, WORD, LRESULT *); - uiControl *c; - - hwnd = (HWND) lParam; - arg3 = HIWORD(wParam); - handler = handlers[hwnd].commandHandler; - c = handlers[hwnd].c; - if (shouldRun(hwnd, handler)) - return (*handler)(c, hwnd, arg3, lResult); - return FALSE; -} - -BOOL runWM_NOTIFY(WPARAM wParam, LPARAM lParam, LRESULT *lResult) -{ - HWND hwnd; - NMHDR *arg3; - BOOL (*handler)(uiControl *, HWND, NMHDR *, LRESULT *); - uiControl *c; - - arg3 = (NMHDR *) lParam; - hwnd = arg3->hwndFrom; - handler = handlers[hwnd].notifyHandler; - c = handlers[hwnd].c; - if (shouldRun(hwnd, handler)) - return (*handler)(c, hwnd, arg3, lResult); - return FALSE; -} - -BOOL runWM_HSCROLL(WPARAM wParam, LPARAM lParam, LRESULT *lResult) -{ - HWND hwnd; - WORD arg3; - BOOL (*handler)(uiControl *, HWND, WORD, LRESULT *); - uiControl *c; - - hwnd = (HWND) lParam; - arg3 = LOWORD(wParam); - handler = handlers[hwnd].hscrollHandler; - c = handlers[hwnd].c; - if (shouldRun(hwnd, handler)) - return (*handler)(c, hwnd, arg3, lResult); - return FALSE; -} - -static std::map wininichanges; - -void uiWindowsRegisterReceiveWM_WININICHANGE(HWND hwnd) -{ - if (wininichanges[hwnd]) - implbug("window handle %p already subscribed to receive WM_WINICHANGEs", hwnd); - wininichanges[hwnd] = true; -} - -void uiWindowsUnregisterReceiveWM_WININICHANGE(HWND hwnd) -{ - if (!wininichanges[hwnd]) - implbug("window handle %p not registered to receive WM_WININICHANGEs", hwnd); - wininichanges[hwnd] = false; -} - -void issueWM_WININICHANGE(WPARAM wParam, LPARAM lParam) -{ - struct wininichange *ch; - - for (const auto &iter : wininichanges) - SendMessageW(iter.first, WM_WININICHANGE, wParam, lParam); -} diff --git a/deps/libui/windows/fontbutton.cpp b/deps/libui/windows/fontbutton.cpp deleted file mode 100644 index d2d4dabfa9..0000000000 --- a/deps/libui/windows/fontbutton.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// 14 april 2016 -#include "uipriv_windows.hpp" - -struct uiFontButton { - uiWindowsControl c; - HWND hwnd; - struct fontDialogParams params; - BOOL already; - void (*onChanged)(uiFontButton *, void *); - void *onChangedData; -}; - -static void uiFontButtonDestroy(uiControl *c) -{ - uiFontButton *b = uiFontButton(c); - - uiWindowsUnregisterWM_COMMANDHandler(b->hwnd); - destroyFontDialogParams(&(b->params)); - uiWindowsEnsureDestroyWindow(b->hwnd); - uiFreeControl(uiControl(b)); -} - -static void updateFontButtonLabel(uiFontButton *b) -{ - WCHAR *text; - - text = fontDialogParamsToString(&(b->params)); - setWindowText(b->hwnd, text); - uiFree(text); - - // changing the text might necessitate a change in the button's size - uiWindowsControlMinimumSizeChanged(uiWindowsControl(b)); -} - -static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult) -{ - uiFontButton *b = uiFontButton(c); - HWND parent; - - if (code != BN_CLICKED) - return FALSE; - - parent = parentToplevel(b->hwnd); - if (showFontDialog(parent, &(b->params))) { - updateFontButtonLabel(b); - (*(b->onChanged))(b, b->onChangedData); - } - - *lResult = 0; - return TRUE; -} - -uiWindowsControlAllDefaultsExceptDestroy(uiFontButton) - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define buttonHeight 14 - -static void uiFontButtonMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiFontButton *b = uiFontButton(c); - SIZE size; - uiWindowsSizing sizing; - int y; - - // try the comctl32 version 6 way - size.cx = 0; // explicitly ask for ideal size - size.cy = 0; - if (SendMessageW(b->hwnd, BCM_GETIDEALSIZE, 0, (LPARAM) (&size)) != FALSE) { - *width = size.cx; - *height = size.cy; - return; - } - - // that didn't work; fall back to using Microsoft's metrics - // Microsoft says to use a fixed width for all buttons; this isn't good enough - // use the text width instead, with some edge padding - *width = uiWindowsWindowTextWidth(b->hwnd) + (2 * GetSystemMetrics(SM_CXEDGE)); - y = buttonHeight; - uiWindowsGetSizing(b->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &y); - *height = y; -} - -static void defaultOnChanged(uiFontButton *b, void *data) -{ - // do nothing -} - -uiDrawTextFont *uiFontButtonFont(uiFontButton *b) -{ - // we don't own b->params.font; we have to add a reference - // we don't own b->params.familyName either; we have to copy it - return mkTextFont(b->params.font, TRUE, b->params.familyName, TRUE, b->params.size); -} - -void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data) -{ - b->onChanged = f; - b->onChangedData = data; -} - -uiFontButton *uiNewFontButton(void) -{ - uiFontButton *b; - - uiWindowsNewControl(uiFontButton, b); - - b->hwnd = uiWindowsEnsureCreateControlHWND(0, - L"button", L"you should not be seeing this", - BS_PUSHBUTTON | WS_TABSTOP, - hInstance, NULL, - TRUE); - - loadInitialFontDialogParams(&(b->params)); - - uiWindowsRegisterWM_COMMANDHandler(b->hwnd, onWM_COMMAND, uiControl(b)); - uiFontButtonOnChanged(b, defaultOnChanged, NULL); - - updateFontButtonLabel(b); - - return b; -} diff --git a/deps/libui/windows/fontdialog.cpp b/deps/libui/windows/fontdialog.cpp deleted file mode 100644 index 603a17dbd2..0000000000 --- a/deps/libui/windows/fontdialog.cpp +++ /dev/null @@ -1,686 +0,0 @@ -// 14 april 2016 -#include "uipriv_windows.hpp" - -// TODOs -// - quote the Choose Font sample here for reference -// - the Choose Font sample defaults to Regular/Italic/Bold/Bold Italic in some case (no styles?); do we? find out what the case is -// - do we set initial family and style topmost as well? -// - this should probably just handle IDWriteFonts - -struct fontDialog { - HWND hwnd; - HWND familyCombobox; - HWND styleCombobox; - HWND sizeCombobox; - - struct fontDialogParams *params; - - fontCollection *fc; - - RECT sampleRect; - HWND sampleBox; - - // we store the current selections in case an invalid string is typed in (partial or nonexistent or invalid number) - // on OK, these are what are read - LRESULT curFamily; - LRESULT curStyle; - double curSize; - - // these are finding the style that's closest to the previous one (these fields) when changing a font - DWRITE_FONT_WEIGHT weight; - DWRITE_FONT_STYLE style; - DWRITE_FONT_STRETCH stretch; -}; - -static LRESULT cbAddString(HWND cb, const WCHAR *str) -{ - LRESULT lr; - - lr = SendMessageW(cb, CB_ADDSTRING, 0, (LPARAM) str); - if (lr == (LRESULT) CB_ERR || lr == (LRESULT) CB_ERRSPACE) - logLastError(L"error adding item to combobox"); - return lr; -} - -static LRESULT cbInsertString(HWND cb, const WCHAR *str, WPARAM pos) -{ - LRESULT lr; - - lr = SendMessageW(cb, CB_INSERTSTRING, pos, (LPARAM) str); - if (lr != (LRESULT) pos) - logLastError(L"error inserting item to combobox"); - return lr; -} - -static LRESULT cbGetItemData(HWND cb, WPARAM item) -{ - LRESULT data; - - data = SendMessageW(cb, CB_GETITEMDATA, item, 0); - if (data == (LRESULT) CB_ERR) - logLastError(L"error getting combobox item data for font dialog"); - return data; -} - -static void cbSetItemData(HWND cb, WPARAM item, LPARAM data) -{ - if (SendMessageW(cb, CB_SETITEMDATA, item, data) == (LRESULT) CB_ERR) - logLastError(L"error setting combobox item data"); -} - -static BOOL cbGetCurSel(HWND cb, LRESULT *sel) -{ - LRESULT n; - - n = SendMessageW(cb, CB_GETCURSEL, 0, 0); - if (n == (LRESULT) CB_ERR) - return FALSE; - if (sel != NULL) - *sel = n; - return TRUE; -} - -static void cbSetCurSel(HWND cb, WPARAM item) -{ - if (SendMessageW(cb, CB_SETCURSEL, item, 0) != (LRESULT) item) - logLastError(L"error selecting combobox item"); -} - -static LRESULT cbGetCount(HWND cb) -{ - LRESULT n; - - n = SendMessageW(cb, CB_GETCOUNT, 0, 0); - if (n == (LRESULT) CB_ERR) - logLastError(L"error getting combobox item count"); - return n; -} - -static void cbWipeAndReleaseData(HWND cb) -{ - IUnknown *obj; - LRESULT i, n; - - n = cbGetCount(cb); - for (i = 0; i < n; i++) { - obj = (IUnknown *) cbGetItemData(cb, (WPARAM) i); - obj->Release(); - } - SendMessageW(cb, CB_RESETCONTENT, 0, 0); -} - -static WCHAR *cbGetItemText(HWND cb, WPARAM item) -{ - LRESULT len; - WCHAR *text; - - // note: neither message includes the terminating L'\0' - len = SendMessageW(cb, CB_GETLBTEXTLEN, item, 0); - if (len == (LRESULT) CB_ERR) - logLastError(L"error getting item text length from combobox"); - text = (WCHAR *) uiAlloc((len + 1) * sizeof (WCHAR), "WCHAR[]"); - if (SendMessageW(cb, CB_GETLBTEXT, item, (LPARAM) text) != len) - logLastError(L"error getting item text from combobox"); - return text; -} - -static BOOL cbTypeToSelect(HWND cb, LRESULT *posOut, BOOL restoreAfter) -{ - WCHAR *text; - LRESULT pos; - DWORD selStart, selEnd; - - // start by saving the current selection as setting the item will change the selection - SendMessageW(cb, CB_GETEDITSEL, (WPARAM) (&selStart), (LPARAM) (&selEnd)); - text = windowText(cb); - pos = SendMessageW(cb, CB_FINDSTRINGEXACT, (WPARAM) (-1), (LPARAM) text); - if (pos == (LRESULT) CB_ERR) { - uiFree(text); - return FALSE; - } - cbSetCurSel(cb, (WPARAM) pos); - if (posOut != NULL) - *posOut = pos; - if (restoreAfter) - if (SendMessageW(cb, WM_SETTEXT, 0, (LPARAM) text) != (LRESULT) TRUE) - logLastError(L"error restoring old combobox text"); - uiFree(text); - // and restore the selection like above - // TODO isn't there a 32-bit version of this - if (SendMessageW(cb, CB_SETEDITSEL, 0, MAKELPARAM(selStart, selEnd)) != (LRESULT) TRUE) - logLastError(L"error restoring combobox edit selection"); - return TRUE; -} - -static void wipeStylesBox(struct fontDialog *f) -{ - cbWipeAndReleaseData(f->styleCombobox); -} - -static WCHAR *fontStyleName(struct fontCollection *fc, IDWriteFont *font) -{ - IDWriteLocalizedStrings *str; - WCHAR *wstr; - HRESULT hr; - - hr = font->GetFaceNames(&str); - if (hr != S_OK) - logHRESULT(L"error getting font style name for font dialog", hr); - wstr = fontCollectionCorrectString(fc, str); - str->Release(); - return wstr; -} - -static void queueRedrawSampleText(struct fontDialog *f) -{ - // TODO TRUE? - invalidateRect(f->sampleBox, NULL, TRUE); -} - -static void styleChanged(struct fontDialog *f) -{ - LRESULT pos; - BOOL selected; - IDWriteFont *font; - - selected = cbGetCurSel(f->styleCombobox, &pos); - if (!selected) // on deselect, do nothing - return; - f->curStyle = pos; - - font = (IDWriteFont *) cbGetItemData(f->styleCombobox, (WPARAM) (f->curStyle)); - // these are for the nearest match when changing the family; see below - f->weight = font->GetWeight(); - f->style = font->GetStyle(); - f->stretch = font->GetStretch(); - - queueRedrawSampleText(f); -} - -static void styleEdited(struct fontDialog *f) -{ - if (cbTypeToSelect(f->styleCombobox, &(f->curStyle), FALSE)) - styleChanged(f); -} - -static void familyChanged(struct fontDialog *f) -{ - LRESULT pos; - BOOL selected; - IDWriteFontFamily *family; - IDWriteFont *font, *matchFont; - DWRITE_FONT_WEIGHT weight; - DWRITE_FONT_STYLE style; - DWRITE_FONT_STRETCH stretch; - UINT32 i, n; - UINT32 matching; - WCHAR *label; - HRESULT hr; - - selected = cbGetCurSel(f->familyCombobox, &pos); - if (!selected) // on deselect, do nothing - return; - f->curFamily = pos; - - family = (IDWriteFontFamily *) cbGetItemData(f->familyCombobox, (WPARAM) (f->curFamily)); - - // for the nearest style match - // when we select a new family, we want the nearest style to the previously selected one to be chosen - // this is how the Choose Font sample does it - hr = family->GetFirstMatchingFont( - f->weight, - f->stretch, - f->style, - &matchFont); - if (hr != S_OK) - logHRESULT(L"error finding first matching font to previous style in font dialog", hr); - // we can't just compare pointers; a "newly created" object comes out - // the Choose Font sample appears to do this instead - weight = matchFont->GetWeight(); - style = matchFont->GetStyle(); - stretch = matchFont->GetStretch(); - matchFont->Release(); - - // TODO test mutliple streteches; all the fonts I have have only one stretch value? - wipeStylesBox(f); - n = family->GetFontCount(); - matching = 0; // a safe/suitable default just in case - for (i = 0; i < n; i++) { - hr = family->GetFont(i, &font); - if (hr != S_OK) - logHRESULT(L"error getting font for filling styles box", hr); - label = fontStyleName(f->fc, font); - pos = cbAddString(f->styleCombobox, label); - uiFree(label); - cbSetItemData(f->styleCombobox, (WPARAM) pos, (LPARAM) font); - if (font->GetWeight() == weight && - font->GetStyle() == style && - font->GetStretch() == stretch) - matching = i; - } - - // and now, load the match - cbSetCurSel(f->styleCombobox, (WPARAM) matching); - styleChanged(f); -} - -// TODO search language variants like the sample does -static void familyEdited(struct fontDialog *f) -{ - if (cbTypeToSelect(f->familyCombobox, &(f->curFamily), FALSE)) - familyChanged(f); -} - -static const struct { - const WCHAR *text; - double value; -} defaultSizes[] = { - { L"8", 8 }, - { L"9", 9 }, - { L"10", 10 }, - { L"11", 11 }, - { L"12", 12 }, - { L"14", 14 }, - { L"16", 16 }, - { L"18", 18 }, - { L"20", 20 }, - { L"22", 22 }, - { L"24", 24 }, - { L"26", 26 }, - { L"28", 28 }, - { L"36", 36 }, - { L"48", 48 }, - { L"72", 72 }, - { NULL, 0 }, -}; - -static void sizeChanged(struct fontDialog *f) -{ - LRESULT pos; - BOOL selected; - - selected = cbGetCurSel(f->sizeCombobox, &pos); - if (!selected) // on deselect, do nothing - return; - f->curSize = defaultSizes[pos].value; - queueRedrawSampleText(f); -} - -static void sizeEdited(struct fontDialog *f) -{ - WCHAR *wsize; - double size; - - // handle type-to-selection - if (cbTypeToSelect(f->sizeCombobox, NULL, FALSE)) { - sizeChanged(f); - return; - } - // selection not chosen, try to parse the typing - wsize = windowText(f->sizeCombobox); - // this is what the Choose Font dialog does; it swallows errors while the real ChooseFont() is not lenient (and only checks on OK) - size = wcstod(wsize, NULL); - if (size <= 0) // don't change on invalid size - return; - f->curSize = size; - queueRedrawSampleText(f); -} - -static void fontDialogDrawSampleText(struct fontDialog *f, ID2D1RenderTarget *rt) -{ - D2D1_COLOR_F color; - D2D1_BRUSH_PROPERTIES props; - ID2D1SolidColorBrush *black; - IDWriteFont *font; - IDWriteLocalizedStrings *sampleStrings; - BOOL exists; - WCHAR *sample; - WCHAR *family; - IDWriteTextFormat *format; - D2D1_RECT_F rect; - HRESULT hr; - - color.r = 0.0; - color.g = 0.0; - color.b = 0.0; - color.a = 1.0; - ZeroMemory(&props, sizeof (D2D1_BRUSH_PROPERTIES)); - props.opacity = 1.0; - // identity matrix - props.transform._11 = 1; - props.transform._22 = 1; - hr = rt->CreateSolidColorBrush( - &color, - &props, - &black); - if (hr != S_OK) - logHRESULT(L"error creating solid brush", hr); - - font = (IDWriteFont *) cbGetItemData(f->styleCombobox, (WPARAM) f->curStyle); - hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT, &sampleStrings, &exists); - if (hr != S_OK) - exists = FALSE; - if (exists) { - sample = fontCollectionCorrectString(f->fc, sampleStrings); - sampleStrings->Release(); - } else - sample = L"The quick brown fox jumps over the lazy dog."; - - // DirectWrite doesn't allow creating a text format from a font; we need to get this ourselves - family = cbGetItemText(f->familyCombobox, f->curFamily); - hr = dwfactory->CreateTextFormat(family, - NULL, - font->GetWeight(), - font->GetStyle(), - font->GetStretch(), - // typographic points are 1/72 inch; this parameter is 1/96 inch - // fortunately Microsoft does this too, in https://msdn.microsoft.com/en-us/library/windows/desktop/dd371554%28v=vs.85%29.aspx - f->curSize * (96.0 / 72.0), - // see http://stackoverflow.com/questions/28397971/idwritefactorycreatetextformat-failing and https://msdn.microsoft.com/en-us/library/windows/desktop/dd368203.aspx - // TODO use the current locale again? - L"", - &format); - if (hr != S_OK) - logHRESULT(L"error creating IDWriteTextFormat", hr); - uiFree(family); - - rect.left = 0; - rect.top = 0; - rect.right = realGetSize(rt).width; - rect.bottom = realGetSize(rt).height; - rt->DrawText(sample, wcslen(sample), - format, - &rect, - black, - // TODO really? - D2D1_DRAW_TEXT_OPTIONS_NONE, - DWRITE_MEASURING_MODE_NATURAL); - - format->Release(); - if (exists) - uiFree(sample); - black->Release(); -} - -static LRESULT CALLBACK fontDialogSampleSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - ID2D1RenderTarget *rt; - struct fontDialog *f; - - switch (uMsg) { - case msgD2DScratchPaint: - rt = (ID2D1RenderTarget *) lParam; - f = (struct fontDialog *) dwRefData; - fontDialogDrawSampleText(f, rt); - return 0; - case WM_NCDESTROY: - if (RemoveWindowSubclass(hwnd, fontDialogSampleSubProc, uIdSubclass) == FALSE) - logLastError(L"error removing font dialog sample text subclass"); - break; - } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -static void setupInitialFontDialogState(struct fontDialog *f) -{ - WCHAR wsize[512]; // this should be way more than enough - LRESULT pos; - - // first let's load the size - // the real font dialog: - // - if the chosen font size is in the list, it selects that item AND makes it topmost - // - if the chosen font size is not in the list, don't bother - // we'll simulate it by setting the text to a %f representation, then pretending as if it was entered - // TODO is 512 the correct number to pass to _snwprintf()? - // TODO will this revert to scientific notation? - _snwprintf(wsize, 512, L"%g", f->params->size); - // TODO make this a setWindowText() - if (SendMessageW(f->sizeCombobox, WM_SETTEXT, 0, (LPARAM) wsize) != (LRESULT) TRUE) - logLastError(L"error setting size combobox to initial font size"); - sizeEdited(f); - if (cbGetCurSel(f->sizeCombobox, &pos)) - if (SendMessageW(f->sizeCombobox, CB_SETTOPINDEX, (WPARAM) pos, 0) != 0) - logLastError(L"error making chosen size topmost in the size combobox"); - - // now we set the family and style - // we do this by first setting the previous style attributes, then simulating a font entered - f->weight = f->params->font->GetWeight(); - f->style = f->params->font->GetStyle(); - f->stretch = f->params->font->GetStretch(); - if (SendMessageW(f->familyCombobox, WM_SETTEXT, 0, (LPARAM) (f->params->familyName)) != (LRESULT) TRUE) - logLastError(L"error setting family combobox to initial font family"); - familyEdited(f); -} - -static struct fontDialog *beginFontDialog(HWND hwnd, LPARAM lParam) -{ - struct fontDialog *f; - UINT32 i, nFamilies; - IDWriteFontFamily *family; - WCHAR *wname; - LRESULT pos; - HWND samplePlacement; - HRESULT hr; - - f = uiNew(struct fontDialog); - f->hwnd = hwnd; - f->params = (struct fontDialogParams *) lParam; - - f->familyCombobox = getDlgItem(f->hwnd, rcFontFamilyCombobox); - f->styleCombobox = getDlgItem(f->hwnd, rcFontStyleCombobox); - f->sizeCombobox = getDlgItem(f->hwnd, rcFontSizeCombobox); - - f->fc = loadFontCollection(); - nFamilies = f->fc->fonts->GetFontFamilyCount(); - for (i = 0; i < nFamilies; i++) { - hr = f->fc->fonts->GetFontFamily(i, &family); - if (hr != S_OK) - logHRESULT(L"error getting font family", hr); - wname = fontCollectionFamilyName(f->fc, family); - pos = cbAddString(f->familyCombobox, wname); - uiFree(wname); - cbSetItemData(f->familyCombobox, (WPARAM) pos, (LPARAM) family); - } - - for (i = 0; defaultSizes[i].text != NULL; i++) - cbInsertString(f->sizeCombobox, defaultSizes[i].text, (WPARAM) i); - - samplePlacement = getDlgItem(f->hwnd, rcFontSamplePlacement); - uiWindowsEnsureGetWindowRect(samplePlacement, &(f->sampleRect)); - mapWindowRect(NULL, f->hwnd, &(f->sampleRect)); - uiWindowsEnsureDestroyWindow(samplePlacement); - f->sampleBox = newD2DScratch(f->hwnd, &(f->sampleRect), (HMENU) rcFontSamplePlacement, fontDialogSampleSubProc, (DWORD_PTR) f); - - setupInitialFontDialogState(f); - return f; -} - -static void endFontDialog(struct fontDialog *f, INT_PTR code) -{ - wipeStylesBox(f); - cbWipeAndReleaseData(f->familyCombobox); - fontCollectionFree(f->fc); - if (EndDialog(f->hwnd, code) == 0) - logLastError(L"error ending font dialog"); - uiFree(f); -} - -static INT_PTR tryFinishDialog(struct fontDialog *f, WPARAM wParam) -{ - IDWriteFontFamily *family; - - // cancelling - if (LOWORD(wParam) != IDOK) { - endFontDialog(f, 1); - return TRUE; - } - - // OK - destroyFontDialogParams(f->params); - f->params->font = (IDWriteFont *) cbGetItemData(f->styleCombobox, f->curStyle); - // we need to save font from being destroyed with the combobox - f->params->font->AddRef(); - f->params->size = f->curSize; - family = (IDWriteFontFamily *) cbGetItemData(f->familyCombobox, f->curFamily); - f->params->familyName = fontCollectionFamilyName(f->fc, family); - f->params->styleName = fontStyleName(f->fc, f->params->font); - endFontDialog(f, 2); - return TRUE; -} - -static INT_PTR CALLBACK fontDialogDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - struct fontDialog *f; - - f = (struct fontDialog *) GetWindowLongPtrW(hwnd, DWLP_USER); - if (f == NULL) { - if (uMsg == WM_INITDIALOG) { - f = beginFontDialog(hwnd, lParam); - SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR) f); - return TRUE; - } - return FALSE; - } - - switch (uMsg) { - case WM_COMMAND: - SetWindowLongPtrW(f->hwnd, DWLP_MSGRESULT, 0); // just in case - switch (LOWORD(wParam)) { - case IDOK: - case IDCANCEL: - if (HIWORD(wParam) != BN_CLICKED) - return FALSE; - return tryFinishDialog(f, wParam); - case rcFontFamilyCombobox: - if (HIWORD(wParam) == CBN_SELCHANGE) { - familyChanged(f); - return TRUE; - } - if (HIWORD(wParam) == CBN_EDITCHANGE) { - familyEdited(f); - return TRUE; - } - return FALSE; - case rcFontStyleCombobox: - if (HIWORD(wParam) == CBN_SELCHANGE) { - styleChanged(f); - return TRUE; - } - if (HIWORD(wParam) == CBN_EDITCHANGE) { - styleEdited(f); - return TRUE; - } - return FALSE; - case rcFontSizeCombobox: - if (HIWORD(wParam) == CBN_SELCHANGE) { - sizeChanged(f); - return TRUE; - } - if (HIWORD(wParam) == CBN_EDITCHANGE) { - sizeEdited(f); - return TRUE; - } - return FALSE; - } - return FALSE; - } - return FALSE; -} - -BOOL showFontDialog(HWND parent, struct fontDialogParams *params) -{ - switch (DialogBoxParamW(hInstance, MAKEINTRESOURCE(rcFontDialog), parent, fontDialogDlgProc, (LPARAM) params)) { - case 1: // cancel - return FALSE; - case 2: // ok - // make the compiler happy by putting the return after the switch - break; - default: - logLastError(L"error running font dialog"); - } - return TRUE; -} - -static IDWriteFontFamily *tryFindFamily(IDWriteFontCollection *fc, const WCHAR *name) -{ - UINT32 index; - BOOL exists; - IDWriteFontFamily *family; - HRESULT hr; - - hr = fc->FindFamilyName(name, &index, &exists); - if (hr != S_OK) - logHRESULT(L"error finding font family for font dialog", hr); - if (!exists) - return NULL; - hr = fc->GetFontFamily(index, &family); - if (hr != S_OK) - logHRESULT(L"error extracting found font family for font dialog", hr); - return family; -} - -void loadInitialFontDialogParams(struct fontDialogParams *params) -{ - struct fontCollection *fc; - IDWriteFontFamily *family; - IDWriteFont *font; - HRESULT hr; - - // Our preferred font is Arial 10 Regular. - // 10 comes from the official font dialog. - // Arial Regular is a reasonable, if arbitrary, default; it's similar to the defaults on other systems. - // If Arial isn't found, we'll use Helvetica and then MS Sans Serif as fallbacks, and if not, we'll just grab the first font family in the collection. - - // We need the correct localized name for Regular (and possibly Arial too? let's say yes to be safe), so let's grab the strings from DirectWrite instead of hardcoding them. - fc = loadFontCollection(); - family = tryFindFamily(fc->fonts, L"Arial"); - if (family == NULL) { - family = tryFindFamily(fc->fonts, L"Helvetica"); - if (family == NULL) { - family = tryFindFamily(fc->fonts, L"MS Sans Serif"); - if (family == NULL) { - hr = fc->fonts->GetFontFamily(0, &family); - if (hr != S_OK) - logHRESULT(L"error getting first font out of font collection (worst case scenario)", hr); - } - } - } - - // next part is simple: just get the closest match to regular - hr = family->GetFirstMatchingFont( - DWRITE_FONT_WEIGHT_NORMAL, - DWRITE_FONT_STRETCH_NORMAL, - DWRITE_FONT_STYLE_NORMAL, - &font); - if (hr != S_OK) - logHRESULT(L"error getting Regular font from Arial", hr); - - params->font = font; - params->size = 10; - params->familyName = fontCollectionFamilyName(fc, family); - params->styleName = fontStyleName(fc, font); - - // don't release font; we still need it - family->Release(); - fontCollectionFree(fc); -} - -void destroyFontDialogParams(struct fontDialogParams *params) -{ - params->font->Release(); - uiFree(params->familyName); - uiFree(params->styleName); -} - -WCHAR *fontDialogParamsToString(struct fontDialogParams *params) -{ - WCHAR *text; - - // TODO dynamically allocate - text = (WCHAR *) uiAlloc(512 * sizeof (WCHAR), "WCHAR[]"); - _snwprintf(text, 512, L"%s %s %g", - params->familyName, - params->styleName, - params->size); - return text; -} diff --git a/deps/libui/windows/form.cpp b/deps/libui/windows/form.cpp deleted file mode 100644 index febcc693bc..0000000000 --- a/deps/libui/windows/form.cpp +++ /dev/null @@ -1,319 +0,0 @@ -// 8 june 2016 -#include "uipriv_windows.hpp" - -struct formChild { - uiControl *c; - HWND label; - int stretchy; - int height; -}; - -struct uiForm { - uiWindowsControl c; - HWND hwnd; - std::vector *controls; - int padded; -}; - -static void formPadding(uiForm *f, int *xpadding, int *ypadding) -{ - uiWindowsSizing sizing; - - *xpadding = 0; - *ypadding = 0; - if (f->padded) { - uiWindowsGetSizing(f->hwnd, &sizing); - uiWindowsSizingStandardPadding(&sizing, xpadding, ypadding); - } -} - -// via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define labelHeight 8 -#define labelYOffset 3 - -static void formRelayout(uiForm *f) -{ - RECT r; - int x, y, width, height; - int xpadding, ypadding; - int nStretchy; - int labelwid, stretchyht; - int thiswid; - int i; - int minimumWidth, minimumHeight; - uiWindowsSizing sizing; - int labelht, labelyoff; - int nVisible; - - if (f->controls->size() == 0) - return; - - uiWindowsEnsureGetClientRect(f->hwnd, &r); - x = r.left; - y = r.top; - width = r.right - r.left; - height = r.bottom - r.top; - - // 0) get this Form's padding - formPadding(f, &xpadding, &ypadding); - - // 1) get width of labels and height of non-stretchy controls - // this will tell us how much space will be left for controls - labelwid = 0; - stretchyht = height; - nStretchy = 0; - nVisible = 0; - for (struct formChild &fc : *(f->controls)) { - if (!uiControlVisible(fc.c)) { - ShowWindow(fc.label, SW_HIDE); - continue; - } - ShowWindow(fc.label, SW_SHOW); - nVisible++; - thiswid = uiWindowsWindowTextWidth(fc.label); - if (labelwid < thiswid) - labelwid = thiswid; - if (fc.stretchy) { - nStretchy++; - continue; - } - uiWindowsControlMinimumSize(uiWindowsControl(fc.c), &minimumWidth, &minimumHeight); - fc.height = minimumHeight; - stretchyht -= minimumHeight; - } - if (nVisible == 0) // nothing to do - return; - - // 2) inset the available rect by the needed padding - width -= xpadding; - height -= (nVisible - 1) * ypadding; - stretchyht -= (nVisible - 1) * ypadding; - - // 3) now get the width of controls and the height of stretchy controls - width -= labelwid; - if (nStretchy != 0) { - stretchyht /= nStretchy; - for (struct formChild &fc : *(f->controls)) { - if (!uiControlVisible(fc.c)) - continue; - if (fc.stretchy) - fc.height = stretchyht; - } - } - - // 4) get the y offset - labelyoff = labelYOffset; - uiWindowsGetSizing(f->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &labelyoff); - - // 5) now we can position controls - // first, make relative to the top-left corner of the container - // also prefer left alignment on Windows - x = labelwid + xpadding; - y = 0; - for (const struct formChild &fc : *(f->controls)) { - if (!uiControlVisible(fc.c)) - continue; - labelht = labelHeight; - uiWindowsGetSizing(f->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &labelht); - uiWindowsEnsureMoveWindowDuringResize(fc.label, 0, y + labelyoff - sizing.InternalLeading, labelwid, labelht); - uiWindowsEnsureMoveWindowDuringResize((HWND) uiControlHandle(fc.c), x, y, width, fc.height); - y += fc.height + ypadding; - } -} - -static void uiFormDestroy(uiControl *c) -{ - uiForm *f = uiForm(c); - - for (const struct formChild &fc : *(f->controls)) { - uiControlSetParent(fc.c, NULL); - uiControlDestroy(fc.c); - uiWindowsEnsureDestroyWindow(fc.label); - } - delete f->controls; - uiWindowsEnsureDestroyWindow(f->hwnd); - uiFreeControl(uiControl(f)); -} - -uiWindowsControlDefaultHandle(uiForm) -uiWindowsControlDefaultParent(uiForm) -uiWindowsControlDefaultSetParent(uiForm) -uiWindowsControlDefaultToplevel(uiForm) -uiWindowsControlDefaultVisible(uiForm) -uiWindowsControlDefaultShow(uiForm) -uiWindowsControlDefaultHide(uiForm) -uiWindowsControlDefaultEnabled(uiForm) -uiWindowsControlDefaultEnable(uiForm) -uiWindowsControlDefaultDisable(uiForm) - -static void uiFormSyncEnableState(uiWindowsControl *c, int enabled) -{ - uiForm *f = uiForm(c); - - if (uiWindowsShouldStopSyncEnableState(uiWindowsControl(f), enabled)) - return; - for (const struct formChild &fc : *(f->controls)) - uiWindowsControlSyncEnableState(uiWindowsControl(fc.c), enabled); -} - -uiWindowsControlDefaultSetParentHWND(uiForm) - -static void uiFormMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiForm *f = uiForm(c); - int xpadding, ypadding; - int nStretchy; - // these two contain the largest minimum width and height of all stretchy controls in the form - // all stretchy controls will use this value to determine the final minimum size - int maxLabelWidth, maxControlWidth; - int maxStretchyHeight; - int labelwid; - int i; - int minimumWidth, minimumHeight; - int nVisible; - uiWindowsSizing sizing; - - *width = 0; - *height = 0; - if (f->controls->size() == 0) - return; - - // 0) get this Form's padding - formPadding(f, &xpadding, &ypadding); - - // 1) determine the longest width of all controls and labels; add in the height of non-stretchy controls and get (but not add in) the largest heights of stretchy controls - // we still add in like direction of stretchy controls - nStretchy = 0; - maxLabelWidth = 0; - maxControlWidth = 0; - maxStretchyHeight = 0; - nVisible = 0; - for (const struct formChild &fc : *(f->controls)) { - if (!uiControlVisible(fc.c)) - continue; - nVisible++; - labelwid = uiWindowsWindowTextWidth(fc.label); - if (maxLabelWidth < labelwid) - maxLabelWidth = labelwid; - uiWindowsControlMinimumSize(uiWindowsControl(fc.c), &minimumWidth, &minimumHeight); - if (fc.stretchy) { - nStretchy++; - if (maxStretchyHeight < minimumHeight) - maxStretchyHeight = minimumHeight; - } - if (maxControlWidth < minimumWidth) - maxControlWidth = minimumWidth; - if (!fc.stretchy) - *height += minimumHeight; - } - if (nVisible == 0) // nothing to show; return 0x0 - return; - *width += maxLabelWidth + maxControlWidth; - - // 2) outset the desired rect with the needed padding - *width += xpadding; - *height += (nVisible - 1) * ypadding; - - // 3) and now we can add in stretchy controls - *height += nStretchy * maxStretchyHeight; -} - -static void uiFormMinimumSizeChanged(uiWindowsControl *c) -{ - uiForm *f = uiForm(c); - - if (uiWindowsControlTooSmall(uiWindowsControl(f))) { - uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(f)); - return; - } - formRelayout(f); -} - -uiWindowsControlDefaultLayoutRect(uiForm) -uiWindowsControlDefaultAssignControlIDZOrder(uiForm) - -static void uiFormChildVisibilityChanged(uiWindowsControl *c) -{ - // TODO eliminate the redundancy - uiWindowsControlMinimumSizeChanged(c); -} - -static void formArrangeChildren(uiForm *f) -{ - LONG_PTR controlID; - HWND insertAfter; - int i; - - controlID = 100; - insertAfter = NULL; - for (const struct formChild &fc : *(f->controls)) { - // TODO assign label ID and z-order - uiWindowsControlAssignControlIDZOrder(uiWindowsControl(fc.c), &controlID, &insertAfter); - } -} - -void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy) -{ - struct formChild fc; - WCHAR *wlabel; - - fc.c = c; - wlabel = toUTF16(label); - fc.label = uiWindowsEnsureCreateControlHWND(0, - L"STATIC", wlabel, - SS_LEFT | SS_NOPREFIX, - hInstance, NULL, - TRUE); - uiFree(wlabel); - uiWindowsEnsureSetParentHWND(fc.label, f->hwnd); - fc.stretchy = stretchy; - uiControlSetParent(fc.c, uiControl(f)); - uiWindowsControlSetParentHWND(uiWindowsControl(fc.c), f->hwnd); - f->controls->push_back(fc); - formArrangeChildren(f); - uiWindowsControlMinimumSizeChanged(uiWindowsControl(f)); -} - -void uiFormDelete(uiForm *f, int index) -{ - struct formChild fc; - - fc = (*(f->controls))[index]; - uiControlSetParent(fc.c, NULL); - uiWindowsControlSetParentHWND(uiWindowsControl(fc.c), NULL); - uiWindowsEnsureDestroyWindow(fc.label); - f->controls->erase(f->controls->begin() + index); - formArrangeChildren(f); - uiWindowsControlMinimumSizeChanged(uiWindowsControl(f)); -} - -int uiFormPadded(uiForm *f) -{ - return f->padded; -} - -void uiFormSetPadded(uiForm *f, int padded) -{ - f->padded = padded; - uiWindowsControlMinimumSizeChanged(uiWindowsControl(f)); -} - -static void onResize(uiWindowsControl *c) -{ - formRelayout(uiForm(c)); -} - -uiForm *uiNewForm(void) -{ - uiForm *f; - - uiWindowsNewControl(uiForm, f); - - f->hwnd = uiWindowsMakeContainer(uiWindowsControl(f), onResize); - - f->controls = new std::vector; - - return f; -} diff --git a/deps/libui/windows/graphemes.cpp b/deps/libui/windows/graphemes.cpp deleted file mode 100644 index 355e403764..0000000000 --- a/deps/libui/windows/graphemes.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// 25 may 2016 -#include "uipriv_windows.hpp" - -// We could use CharNext() to generate grapheme cluster boundaries, but it doesn't handle surrogate pairs properly (see http://archives.miloush.net/michkap/archive/2008/12/16/9223301.html). -// So let's use Uniscribe (see http://archives.miloush.net/michkap/archive/2005/01/14/352802.html) -// See also http://www.catch22.net/tuts/uniscribe-mysteries and http://www.catch22.net/tuts/keyboard-navigation for more details. - -static HRESULT itemize(WCHAR *msg, size_t len, SCRIPT_ITEM **out, int *outn) -{ - SCRIPT_CONTROL sc; - SCRIPT_STATE ss; - SCRIPT_ITEM *items; - size_t maxItems; - int n; - HRESULT hr; - - // make sure these are zero-initialized to avoid mangling the text - ZeroMemory(&sc, sizeof (SCRIPT_CONTROL)); - ZeroMemory(&ss, sizeof (SCRIPT_STATE)); - - maxItems = len + 2; - for (;;) { - items = new SCRIPT_ITEM[maxItems]; - hr = ScriptItemize(msg, len, - maxItems, - &sc, &ss, - items, &n); - if (hr == S_OK) - break; - // otherwise either an error or not enough room - delete[] items; - if (hr != E_OUTOFMEMORY) - return hr; - maxItems *= 2; // add some more and try again - } - - *out = items; - *outn = n; - return S_OK; -} - -size_t *graphemes(WCHAR *msg) -{ - size_t len; - SCRIPT_ITEM *items; - int i, n; - size_t *out; - size_t *op; - SCRIPT_LOGATTR *logattr; - int j, nn; - HRESULT hr; - - len = wcslen(msg); - hr = itemize(msg, len, &items, &n); - if (hr != S_OK) - logHRESULT(L"error itemizing string for finding grapheme cluster boundaries", hr); - - // should be enough; 2 more just to be safe - out = (size_t *) uiAlloc((len + 2) * sizeof (size_t), "size_t[]"); - op = out; - - // note that there are actually n + 1 elements in items - for (i = 0; i < n; i++) { - nn = items[i + 1].iCharPos - items[i].iCharPos; - logattr = new SCRIPT_LOGATTR[nn]; - hr = ScriptBreak(msg + items[i].iCharPos, nn, - &(items[i].a), logattr); - if (hr != S_OK) - logHRESULT(L"error breaking string for finding grapheme cluster boundaries", hr); - for (j = 0; j < nn; j++) - if (logattr[j].fCharStop != 0) - *op++ = items[i].iCharPos + j; - delete[] logattr; - } - // and handle the last item for the end of the string - *op++ = items[i].iCharPos; - - delete[] items; - return out; -} diff --git a/deps/libui/windows/grid.cpp b/deps/libui/windows/grid.cpp deleted file mode 100644 index c63cd1e4a8..0000000000 --- a/deps/libui/windows/grid.cpp +++ /dev/null @@ -1,658 +0,0 @@ -// 10 june 2016 -#include "uipriv_windows.hpp" - -// TODO compare with GTK+: -// - what happens if you call InsertAt() twice? -// - what happens if you call Append() twice? - -// TODOs -// - the Assorted page has clipping and repositioning issues - -struct gridChild { - uiControl *c; - int left; - int top; - int xspan; - int yspan; - int hexpand; - uiAlign halign; - int vexpand; - uiAlign valign; - - // have these here so they don't need to be reallocated each relayout - int finalx, finaly; - int finalwidth, finalheight; - int minwidth, minheight; -}; - -struct uiGrid { - uiWindowsControl c; - HWND hwnd; - std::vector *children; - std::map *indexof; - int padded; - - int xmin, ymin; - int xmax, ymax; -}; - -static bool gridRecomputeMinMax(uiGrid *g) -{ - bool first = true; - - for (struct gridChild *gc : *(g->children)) { - // this is important; we want g->xmin/g->ymin to satisfy gridLayoutData::visibleRow()/visibleColumn() - if (!uiControlVisible(gc->c)) - continue; - if (first) { - g->xmin = gc->left; - g->ymin = gc->top; - g->xmax = gc->left + gc->xspan; - g->ymax = gc->top + gc->yspan; - first = false; - continue; - } - if (g->xmin > gc->left) - g->xmin = gc->left; - if (g->ymin > gc->top) - g->ymin = gc->top; - if (g->xmax < (gc->left + gc->xspan)) - g->xmax = gc->left + gc->xspan; - if (g->ymax < (gc->top + gc->yspan)) - g->ymax = gc->top + gc->yspan; - } - return first != false; -} - -#define xcount(g) ((g)->xmax - (g)->xmin) -#define ycount(g) ((g)->ymax - (g)->ymin) -#define toxindex(g, x) ((x) - (g)->xmin) -#define toyindex(g, y) ((y) - (g)->ymin) - -class gridLayoutData { - int ycount; -public: - int **gg; // topological map gg[y][x] = control index - int *colwidths; - int *rowheights; - bool *hexpand; - bool *vexpand; - int nVisibleRows; - int nVisibleColumns; - - bool noVisible; - - gridLayoutData(uiGrid *g) - { - size_t i; - int x, y; - - this->noVisible = gridRecomputeMinMax(g); - - this->gg = new int *[ycount(g)]; - for (y = 0; y < ycount(g); y++) { - this->gg[y] = new int[xcount(g)]; - for (x = 0; x < xcount(g); x++) - this->gg[y][x] = -1; - } - - for (i = 0; i < g->children->size(); i++) { - struct gridChild *gc; - - gc = (*(g->children))[i]; - if (!uiControlVisible(gc->c)) - continue; - for (y = gc->top; y < gc->top + gc->yspan; y++) - for (x = gc->left; x < gc->left + gc->xspan; x++) - this->gg[toyindex(g, y)][toxindex(g, x)] = i; - } - - this->colwidths = new int[xcount(g)]; - ZeroMemory(this->colwidths, xcount(g) * sizeof (int)); - this->rowheights = new int[ycount(g)]; - ZeroMemory(this->rowheights, ycount(g) * sizeof (int)); - this->hexpand = new bool[xcount(g)]; - ZeroMemory(this->hexpand, xcount(g) * sizeof (bool)); - this->vexpand = new bool[ycount(g)]; - ZeroMemory(this->vexpand, ycount(g) * sizeof (bool)); - - this->ycount = ycount(g); - - // if a row or column only contains emptys and spanning cells of a opposite-direction spannings, it is invisible and should not be considered for padding amount calculations - // note that the first row and column will always be visible because gridRecomputeMinMax() computed a smallest fitting rectangle - if (this->noVisible) - return; - this->nVisibleRows = 0; - for (y = 0; y < this->ycount; y++) - if (this->visibleRow(g, y)) - this->nVisibleRows++; - this->nVisibleColumns = 0; - for (x = 0; x < xcount(g); x++) - if (this->visibleColumn(g, x)) - this->nVisibleColumns++; - } - - ~gridLayoutData() - { - size_t y; - - delete[] this->hexpand; - delete[] this->vexpand; - delete[] this->colwidths; - delete[] this->rowheights; - for (y = 0; y < this->ycount; y++) - delete[] this->gg[y]; - delete[] this->gg; - } - - bool visibleRow(uiGrid *g, int y) - { - int x; - struct gridChild *gc; - - for (x = 0; x < xcount(g); x++) - if (this->gg[y][x] != -1) { - gc = (*(g->children))[this->gg[y][x]]; - if (gc->yspan == 1 || gc->top - g->ymin == y) - return true; - } - return false; - } - - bool visibleColumn(uiGrid *g, int x) - { - int y; - struct gridChild *gc; - - for (y = 0; y < this->ycount; y++) - if (this->gg[y][x] != -1) { - gc = (*(g->children))[this->gg[y][x]]; - if (gc->xspan == 1 || gc->left - g->xmin == x) - return true; - } - return false; - } -}; - -static void gridPadding(uiGrid *g, int *xpadding, int *ypadding) -{ - uiWindowsSizing sizing; - - *xpadding = 0; - *ypadding = 0; - if (g->padded) { - uiWindowsGetSizing(g->hwnd, &sizing); - uiWindowsSizingStandardPadding(&sizing, xpadding, ypadding); - } -} - -static void gridRelayout(uiGrid *g) -{ - RECT r; - int x, y, width, height; - gridLayoutData *ld; - int xpadding, ypadding; - int ix, iy; - int iwidth, iheight; - int i; - struct gridChild *gc; - int nhexpand, nvexpand; - - if (g->children->size() == 0) - return; // nothing to do - - uiWindowsEnsureGetClientRect(g->hwnd, &r); - x = r.left; - y = r.top; - width = r.right - r.left; - height = r.bottom - r.top; - - gridPadding(g, &xpadding, &ypadding); - ld = new gridLayoutData(g); - if (ld->noVisible) { // nothing to do - delete ld; - return; - } - - // 0) discount padding from width/height - width -= (ld->nVisibleColumns - 1) * xpadding; - height -= (ld->nVisibleRows - 1) * ypadding; - - // 1) compute colwidths and rowheights before handling expansion - // we only count non-spanning controls to avoid weirdness - for (iy = 0; iy < ycount(g); iy++) - for (ix = 0; ix < xcount(g); ix++) { - i = ld->gg[iy][ix]; - if (i == -1) - continue; - gc = (*(g->children))[i]; - uiWindowsControlMinimumSize(uiWindowsControl(gc->c), &iwidth, &iheight); - if (gc->xspan == 1) - if (ld->colwidths[ix] < iwidth) - ld->colwidths[ix] = iwidth; - if (gc->yspan == 1) - if (ld->rowheights[iy] < iheight) - ld->rowheights[iy] = iheight; - // save these for step 6 - gc->minwidth = iwidth; - gc->minheight = iheight; - } - - // 2) figure out which rows/columns expand but not span - // we need to know which expanding rows/columns don't span before we can handle the ones that do - for (i = 0; i < g->children->size(); i++) { - gc = (*(g->children))[i]; - if (!uiControlVisible(gc->c)) - continue; - if (gc->hexpand && gc->xspan == 1) - ld->hexpand[toxindex(g, gc->left)] = true; - if (gc->vexpand && gc->yspan == 1) - ld->vexpand[toyindex(g, gc->top)] = true; - } - - // 3) figure out which rows/columns expand that do span - // the way we handle this is simple: if none of the spanned rows/columns expand, make all rows/columns expand - for (i = 0; i < g->children->size(); i++) { - gc = (*(g->children))[i]; - if (!uiControlVisible(gc->c)) - continue; - if (gc->hexpand && gc->xspan != 1) { - bool doit = true; - - for (ix = gc->left; ix < gc->left + gc->xspan; ix++) - if (ld->hexpand[toxindex(g, ix)]) { - doit = false; - break; - } - if (doit) - for (ix = gc->left; ix < gc->left + gc->xspan; ix++) - ld->hexpand[toxindex(g, ix)] = true; - } - if (gc->vexpand && gc->yspan != 1) { - bool doit = true; - - for (iy = gc->top; iy < gc->top + gc->yspan; iy++) - if (ld->vexpand[toyindex(g, iy)]) { - doit = false; - break; - } - if (doit) - for (iy = gc->top; iy < gc->top + gc->yspan; iy++) - ld->vexpand[toyindex(g, iy)] = true; - } - } - - // 4) compute and assign expanded widths/heights - nhexpand = 0; - nvexpand = 0; - for (i = 0; i < xcount(g); i++) - if (ld->hexpand[i]) - nhexpand++; - else - width -= ld->colwidths[i]; - for (i = 0; i < ycount(g); i++) - if (ld->vexpand[i]) - nvexpand++; - else - height -= ld->rowheights[i]; - for (i = 0; i < xcount(g); i++) - if (ld->hexpand[i]) - ld->colwidths[i] = width / nhexpand; - for (i = 0; i < ycount(g); i++) - if (ld->vexpand[i]) - ld->rowheights[i] = height / nvexpand; - - // 5) reset the final coordinates for the next step - for (i = 0; i < g->children->size(); i++) { - gc = (*(g->children))[i]; - if (!uiControlVisible(gc->c)) - continue; - gc->finalx = 0; - gc->finaly = 0; - gc->finalwidth = 0; - gc->finalheight = 0; - } - - // 6) compute cell positions and sizes - for (iy = 0; iy < ycount(g); iy++) { - int curx; - int prev; - - curx = 0; - prev = -1; - for (ix = 0; ix < xcount(g); ix++) { - if (!ld->visibleColumn(g, ix)) - continue; - i = ld->gg[iy][ix]; - if (i != -1) { - gc = (*(g->children))[i]; - if (iy == toyindex(g, gc->top)) { // don't repeat this step if the control spans vertically - if (i != prev) - gc->finalx = curx; - else - gc->finalwidth += xpadding; - gc->finalwidth += ld->colwidths[ix]; - } - } - curx += ld->colwidths[ix] + xpadding; - prev = i; - } - } - for (ix = 0; ix < xcount(g); ix++) { - int cury; - int prev; - - cury = 0; - prev = -1; - for (iy = 0; iy < ycount(g); iy++) { - if (!ld->visibleRow(g, iy)) - continue; - i = ld->gg[iy][ix]; - if (i != -1) { - gc = (*(g->children))[i]; - if (ix == toxindex(g, gc->left)) { // don't repeat this step if the control spans horizontally - if (i != prev) - gc->finaly = cury; - else - gc->finalheight += ypadding; - gc->finalheight += ld->rowheights[iy]; - } - } - cury += ld->rowheights[iy] + ypadding; - prev = i; - } - } - - // 7) everything as it stands now is set for xalign == Fill yalign == Fill; set the correct alignments - // this is why we saved minwidth/minheight above - for (i = 0; i < g->children->size(); i++) { - gc = (*(g->children))[i]; - if (!uiControlVisible(gc->c)) - continue; - if (gc->halign != uiAlignFill) { - switch (gc->halign) { - case uiAlignEnd: - gc->finalx += gc->finalwidth - gc->minwidth; - break; - case uiAlignCenter: - gc->finalx += (gc->finalwidth - gc->minwidth) / 2; - break; - } - gc->finalwidth = gc->minwidth; // for all three - } - if (gc->valign != uiAlignFill) { - switch (gc->valign) { - case uiAlignEnd: - gc->finaly += gc->finalheight - gc->minheight; - break; - case uiAlignCenter: - gc->finaly += (gc->finalheight - gc->minheight) / 2; - break; - } - gc->finalheight = gc->minheight; // for all three - } - } - - // 8) and FINALLY we resize - for (iy = 0; iy < ycount(g); iy++) - for (ix = 0; ix < xcount(g); ix++) { - i = ld->gg[iy][ix]; - if (i != -1) { // treat empty cells like spaces - gc = (*(g->children))[i]; - uiWindowsEnsureMoveWindowDuringResize( - (HWND) uiControlHandle(gc->c), - gc->finalx,//TODO + x, - gc->finaly,//TODO + y, - gc->finalwidth, - gc->finalheight); - } - } - - delete ld; -} - -static void uiGridDestroy(uiControl *c) -{ - uiGrid *g = uiGrid(c); - - for (struct gridChild *gc : *(g->children)) { - uiControlSetParent(gc->c, NULL); - uiControlDestroy(gc->c); - uiFree(gc); - } - delete g->indexof; - delete g->children; - uiWindowsEnsureDestroyWindow(g->hwnd); - uiFreeControl(uiControl(g)); -} - -uiWindowsControlDefaultHandle(uiGrid) -uiWindowsControlDefaultParent(uiGrid) -uiWindowsControlDefaultSetParent(uiGrid) -uiWindowsControlDefaultToplevel(uiGrid) -uiWindowsControlDefaultVisible(uiGrid) -uiWindowsControlDefaultShow(uiGrid) -uiWindowsControlDefaultHide(uiGrid) -uiWindowsControlDefaultEnabled(uiGrid) -uiWindowsControlDefaultEnable(uiGrid) -uiWindowsControlDefaultDisable(uiGrid) - -static void uiGridSyncEnableState(uiWindowsControl *c, int enabled) -{ - uiGrid *g = uiGrid(c); - - if (uiWindowsShouldStopSyncEnableState(uiWindowsControl(g), enabled)) - return; - for (const struct gridChild *gc : *(g->children)) - uiWindowsControlSyncEnableState(uiWindowsControl(gc->c), enabled); -} - -uiWindowsControlDefaultSetParentHWND(uiGrid) - -static void uiGridMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiGrid *g = uiGrid(c); - int xpadding, ypadding; - gridLayoutData *ld; - int x, y; - int i; - struct gridChild *gc; - int minwid, minht; - int colwidth, rowheight; - - *width = 0; - *height = 0; - if (g->children->size() == 0) - return; // nothing to do - - gridPadding(g, &xpadding, &ypadding); - ld = new gridLayoutData(g); - if (ld->noVisible) { // nothing to do; return 0x0 - delete ld; - return; - } - - // 1) compute colwidths and rowheights before handling expansion - // TODO put this in its own function (but careful about the spanning calculation in gridRelayout()) - for (y = 0; y < ycount(g); y++) - for (x = 0; x < xcount(g); x++) { - i = ld->gg[y][x]; - if (i == -1) - continue; - gc = (*(g->children))[i]; - uiWindowsControlMinimumSize(uiWindowsControl(gc->c), &minwid, &minht); - // allot equal space in the presence of spanning to keep things sane - if (ld->colwidths[x] < minwid / gc->xspan) - ld->colwidths[x] = minwid / gc->xspan; - if (ld->rowheights[y] < minht / gc->yspan) - ld->rowheights[y] = minht / gc->yspan; - // save these for step 6 - gc->minwidth = minwid; - gc->minheight = minht; - } - - // 2) compute total column width/row height - colwidth = 0; - rowheight = 0; - for (x = 0; x < xcount(g); x++) - colwidth += ld->colwidths[x]; - for (y = 0; y < ycount(g); y++) - rowheight += ld->rowheights[y]; - - // and that's it; just account for padding - *width = colwidth + (ld->nVisibleColumns - 1) * xpadding; - *height = rowheight + (ld->nVisibleRows - 1) * ypadding; -} - -static void uiGridMinimumSizeChanged(uiWindowsControl *c) -{ - uiGrid *g = uiGrid(c); - - if (uiWindowsControlTooSmall(uiWindowsControl(g))) { - uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(g)); - return; - } - gridRelayout(g); -} - -uiWindowsControlDefaultLayoutRect(uiGrid) -uiWindowsControlDefaultAssignControlIDZOrder(uiGrid) - -static void uiGridChildVisibilityChanged(uiWindowsControl *c) -{ - // TODO eliminate the redundancy - uiWindowsControlMinimumSizeChanged(c); -} - -// must have called gridRecomputeMinMax() first -static void gridArrangeChildren(uiGrid *g) -{ - LONG_PTR controlID; - HWND insertAfter; - gridLayoutData *ld; - bool *visited; - int x, y; - int i; - struct gridChild *gc; - - if (g->children->size() == 0) - return; // nothing to do - ld = new gridLayoutData(g); - controlID = 100; - insertAfter = NULL; - visited = new bool[g->children->size()]; - ZeroMemory(visited, g->children->size() * sizeof (bool)); - for (y = 0; y < ycount(g); y++) - for (x = 0; x < xcount(g); x++) { - i = ld->gg[y][x]; - if (i == -1) - continue; - if (visited[i]) - continue; - visited[i] = true; - gc = (*(g->children))[i]; - uiWindowsControlAssignControlIDZOrder(uiWindowsControl(gc->c), &controlID, &insertAfter); - } - delete[] visited; - delete ld; -} - -static struct gridChild *toChild(uiControl *c, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - struct gridChild *gc; - - if (xspan < 0) - userbug("You cannot have a negative xspan in a uiGrid cell."); - if (yspan < 0) - userbug("You cannot have a negative yspan in a uiGrid cell."); - gc = uiNew(struct gridChild); - gc->c = c; - gc->xspan = xspan; - gc->yspan = yspan; - gc->hexpand = hexpand; - gc->halign = halign; - gc->vexpand = vexpand; - gc->valign = valign; - return gc; -} - -static void add(uiGrid *g, struct gridChild *gc) -{ - uiControlSetParent(gc->c, uiControl(g)); - uiWindowsControlSetParentHWND(uiWindowsControl(gc->c), g->hwnd); - g->children->push_back(gc); - (*(g->indexof))[gc->c] = g->children->size() - 1; - gridRecomputeMinMax(g); - gridArrangeChildren(g); - uiWindowsControlMinimumSizeChanged(uiWindowsControl(g)); -} - -void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - struct gridChild *gc; - - gc = toChild(c, xspan, yspan, hexpand, halign, vexpand, valign); - gc->left = left; - gc->top = top; - add(g, gc); -} - -// TODO decide what happens if existing is NULL -void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - struct gridChild *gc; - struct gridChild *other; - - gc = toChild(c, xspan, yspan, hexpand, halign, vexpand, valign); - other = (*(g->children))[(*(g->indexof))[existing]]; - switch (at) { - case uiAtLeading: - gc->left = other->left - gc->xspan; - gc->top = other->top; - break; - case uiAtTop: - gc->left = other->left; - gc->top = other->top - gc->yspan; - break; - case uiAtTrailing: - gc->left = other->left + other->xspan; - gc->top = other->top; - break; - case uiAtBottom: - gc->left = other->left; - gc->top = other->top + other->yspan; - break; - // TODO add error checks to ALL enums - } - add(g, gc); -} - -int uiGridPadded(uiGrid *g) -{ - return g->padded; -} - -void uiGridSetPadded(uiGrid *g, int padded) -{ - g->padded = padded; - uiWindowsControlMinimumSizeChanged(uiWindowsControl(g)); -} - -static void onResize(uiWindowsControl *c) -{ - gridRelayout(uiGrid(c)); -} - -uiGrid *uiNewGrid(void) -{ - uiGrid *g; - - uiWindowsNewControl(uiGrid, g); - - g->hwnd = uiWindowsMakeContainer(uiWindowsControl(g), onResize); - - g->children = new std::vector; - g->indexof = new std::map; - - return g; -} diff --git a/deps/libui/windows/group.cpp b/deps/libui/windows/group.cpp deleted file mode 100644 index 8824c5a4d7..0000000000 --- a/deps/libui/windows/group.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// 16 may 2015 -#include "uipriv_windows.hpp" - -struct uiGroup { - uiWindowsControl c; - HWND hwnd; - struct uiControl *child; - int margined; -}; - -// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define groupXMargin 6 -#define groupYMarginTop 11 /* note this value /includes/ the groupbox label */ -#define groupYMarginBottom 7 - -// unfortunately because the client area of a groupbox includes the frame and caption text, we have to apply some margins ourselves, even if we don't want "any" -// these were deduced by hand based on the standard DLU conversions; the X and Y top margins are the width and height, respectively, of one character cell -// they can be fine-tuned later -#define groupUnmarginedXMargin 4 -#define groupUnmarginedYMarginTop 8 -#define groupUnmarginedYMarginBottom 3 - -static void groupMargins(uiGroup *g, int *mx, int *mtop, int *mbottom) -{ - uiWindowsSizing sizing; - - *mx = groupUnmarginedXMargin; - *mtop = groupUnmarginedYMarginTop; - *mbottom = groupUnmarginedYMarginBottom; - if (g->margined) { - *mx = groupXMargin; - *mtop = groupYMarginTop; - *mbottom = groupYMarginBottom; - } - uiWindowsGetSizing(g->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, mx, mtop); - uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, mbottom); -} - -static void groupRelayout(uiGroup *g) -{ - RECT r; - int mx, mtop, mbottom; - - if (g->child == NULL) - return; - uiWindowsEnsureGetClientRect(g->hwnd, &r); - groupMargins(g, &mx, &mtop, &mbottom); - r.left += mx; - r.top += mtop; - r.right -= mx; - r.bottom -= mbottom; - uiWindowsEnsureMoveWindowDuringResize((HWND) uiControlHandle(g->child), r.left, r.top, r.right - r.left, r.bottom - r.top); -} - -static void uiGroupDestroy(uiControl *c) -{ - uiGroup *g = uiGroup(c); - - if (g->child != NULL) { - uiControlSetParent(g->child, NULL); - uiControlDestroy(g->child); - } - uiWindowsEnsureDestroyWindow(g->hwnd); - uiFreeControl(uiControl(g)); -} - -uiWindowsControlDefaultHandle(uiGroup) -uiWindowsControlDefaultParent(uiGroup) -uiWindowsControlDefaultSetParent(uiGroup) -uiWindowsControlDefaultToplevel(uiGroup) -uiWindowsControlDefaultVisible(uiGroup) -uiWindowsControlDefaultShow(uiGroup) -uiWindowsControlDefaultHide(uiGroup) -uiWindowsControlDefaultEnabled(uiGroup) -uiWindowsControlDefaultEnable(uiGroup) -uiWindowsControlDefaultDisable(uiGroup) - -static void uiGroupSyncEnableState(uiWindowsControl *c, int enabled) -{ - uiGroup *g = uiGroup(c); - - if (uiWindowsShouldStopSyncEnableState(uiWindowsControl(g), enabled)) - return; - EnableWindow(g->hwnd, enabled); - if (g->child != NULL) - uiWindowsControlSyncEnableState(uiWindowsControl(g->child), enabled); -} - -uiWindowsControlDefaultSetParentHWND(uiGroup) - -static void uiGroupMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiGroup *g = uiGroup(c); - int mx, mtop, mbottom; - int labelWidth; - - *width = 0; - *height = 0; - if (g->child != NULL) - uiWindowsControlMinimumSize(uiWindowsControl(g->child), width, height); - labelWidth = uiWindowsWindowTextWidth(g->hwnd); - if (*width < labelWidth) // don't clip the label; it doesn't ellipsize - *width = labelWidth; - groupMargins(g, &mx, &mtop, &mbottom); - *width += 2 * mx; - *height += mtop + mbottom; -} - -static void uiGroupMinimumSizeChanged(uiWindowsControl *c) -{ - uiGroup *g = uiGroup(c); - - if (uiWindowsControlTooSmall(uiWindowsControl(g))) { - uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(g)); - return; - } - groupRelayout(g); -} - -uiWindowsControlDefaultLayoutRect(uiGroup) -uiWindowsControlDefaultAssignControlIDZOrder(uiGroup) - -static void uiGroupChildVisibilityChanged(uiWindowsControl *c) -{ - // TODO eliminate the redundancy - uiWindowsControlMinimumSizeChanged(c); -} - -char *uiGroupTitle(uiGroup *g) -{ - return uiWindowsWindowText(g->hwnd); -} - -void uiGroupSetTitle(uiGroup *g, const char *text) -{ - uiWindowsSetWindowText(g->hwnd, text); - // changing the text might necessitate a change in the groupbox's size - uiWindowsControlMinimumSizeChanged(uiWindowsControl(g)); -} - -void uiGroupSetChild(uiGroup *g, uiControl *child) -{ - if (g->child != NULL) { - uiControlSetParent(g->child, NULL); - uiWindowsControlSetParentHWND(uiWindowsControl(g->child), NULL); - } - g->child = child; - if (g->child != NULL) { - uiControlSetParent(g->child, uiControl(g)); - uiWindowsControlSetParentHWND(uiWindowsControl(g->child), g->hwnd); - uiWindowsControlAssignSoleControlIDZOrder(uiWindowsControl(g->child)); - uiWindowsControlMinimumSizeChanged(uiWindowsControl(g)); - } -} - -int uiGroupMargined(uiGroup *g) -{ - return g->margined; -} - -void uiGroupSetMargined(uiGroup *g, int margined) -{ - g->margined = margined; - uiWindowsControlMinimumSizeChanged(uiWindowsControl(g)); -} - -static LRESULT CALLBACK groupSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - uiGroup *g = uiGroup(dwRefData); - WINDOWPOS *wp = (WINDOWPOS *) lParam; - MINMAXINFO *mmi = (MINMAXINFO *) lParam; - int minwid, minht; - LRESULT lResult; - - if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE) - return lResult; - switch (uMsg) { - case WM_WINDOWPOSCHANGED: - if ((wp->flags & SWP_NOSIZE) != 0) - break; - groupRelayout(g); - return 0; - case WM_GETMINMAXINFO: - lResult = DefWindowProcW(hwnd, uMsg, wParam, lParam); - uiWindowsControlMinimumSize(uiWindowsControl(g), &minwid, &minht); - mmi->ptMinTrackSize.x = minwid; - mmi->ptMinTrackSize.y = minht; - return lResult; - case WM_NCDESTROY: - if (RemoveWindowSubclass(hwnd, groupSubProc, uIdSubclass) == FALSE) - logLastError(L"error removing groupbox subclass"); - break; - } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -uiGroup *uiNewGroup(const char *text) -{ - uiGroup *g; - WCHAR *wtext; - - uiWindowsNewControl(uiGroup, g); - - wtext = toUTF16(text); - g->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CONTROLPARENT, - L"button", wtext, - BS_GROUPBOX, - hInstance, NULL, - TRUE); - uiFree(wtext); - - if (SetWindowSubclass(g->hwnd, groupSubProc, 0, (DWORD_PTR) g) == FALSE) - logLastError(L"error subclassing groupbox to handle parent messages"); - - return g; -} diff --git a/deps/libui/windows/init.cpp b/deps/libui/windows/init.cpp deleted file mode 100644 index 228741653c..0000000000 --- a/deps/libui/windows/init.cpp +++ /dev/null @@ -1,167 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.hpp" - -HINSTANCE hInstance; -int nCmdShow; - -HFONT hMessageFont; - -// LONGTERM needed? -HBRUSH hollowBrush; - -// the returned pointer is actually to the second character -// if the first character is - then free, otherwise don't -static const char *initerr(const char *message, const WCHAR *label, DWORD value) -{ - WCHAR *sysmsg; - BOOL hassysmsg; - WCHAR *wmessage; - WCHAR *wout; - char *out; - - hassysmsg = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, value, 0, (LPWSTR) (&sysmsg), 0, NULL) != 0; - if (!hassysmsg) - sysmsg = L""; - wmessage = toUTF16(message + 1); - wout = strf(L"-error initializing libui: %s; code %I32d (0x%08I32X) %s", - wmessage, - value, value, - sysmsg); - uiFree(wmessage); - if (hassysmsg) - LocalFree(sysmsg); // ignore error - out = toUTF8(wout); - uiFree(wout); - return out + 1; -} - -#define ieLastErr(msg) initerr("=" msg, L"GetLastError() ==", GetLastError()) -#define ieHRESULT(msg, hr) initerr("=" msg, L"HRESULT", (DWORD) hr) - -// LONGTERM make common -uiInitOptions options; - -#define wantedICCClasses ( \ - ICC_STANDARD_CLASSES | /* user32.dll controls */ \ - ICC_PROGRESS_CLASS | /* progress bars */ \ - ICC_TAB_CLASSES | /* tabs */ \ - ICC_LISTVIEW_CLASSES | /* table headers */ \ - ICC_UPDOWN_CLASS | /* spinboxes */ \ - ICC_BAR_CLASSES | /* trackbar */ \ - ICC_DATE_CLASSES | /* date/time picker */ \ - 0) - -const char *uiInit(uiInitOptions *o) -{ - STARTUPINFOW si; - const char *ce; - HICON hDefaultIcon; - HCURSOR hDefaultCursor; - NONCLIENTMETRICSW ncm; - INITCOMMONCONTROLSEX icc; - HRESULT hr; - - options = *o; - - initAlloc(); - - nCmdShow = SW_SHOWDEFAULT; - GetStartupInfoW(&si); - if ((si.dwFlags & STARTF_USESHOWWINDOW) != 0) - nCmdShow = si.wShowWindow; - - // LONGTERM set DPI awareness - - hDefaultIcon = LoadIconW(NULL, IDI_APPLICATION); - if (hDefaultIcon == NULL) - return ieLastErr("loading default icon for window classes"); - hDefaultCursor = LoadCursorW(NULL, IDC_ARROW); - if (hDefaultCursor == NULL) - return ieLastErr("loading default cursor for window classes"); - - ce = initUtilWindow(hDefaultIcon, hDefaultCursor); - if (ce != NULL) - return initerr(ce, L"GetLastError() ==", GetLastError()); - - if (registerWindowClass(hDefaultIcon, hDefaultCursor) == 0) - return ieLastErr("registering uiWindow window class"); - - ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW)); - ncm.cbSize = sizeof (NONCLIENTMETRICSW); - if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0) - return ieLastErr("getting default fonts"); - hMessageFont = CreateFontIndirectW(&(ncm.lfMessageFont)); - if (hMessageFont == NULL) - return ieLastErr("loading default messagebox font; this is the default UI font"); - - if (initContainer(hDefaultIcon, hDefaultCursor) == 0) - return ieLastErr("initializing uiWindowsMakeContainer() window class"); - - hollowBrush = (HBRUSH) GetStockObject(HOLLOW_BRUSH); - if (hollowBrush == NULL) - return ieLastErr("getting hollow brush"); - - ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX)); - icc.dwSize = sizeof (INITCOMMONCONTROLSEX); - icc.dwICC = wantedICCClasses; - if (InitCommonControlsEx(&icc) == 0) - return ieLastErr("initializing Common Controls"); - - hr = CoInitialize(NULL); - if (hr != S_OK && hr != S_FALSE) - return ieHRESULT("initializing COM", hr); - // LONGTERM initialize COM security - // LONGTERM (windows vista) turn off COM exception handling - - hr = initDraw(); - if (hr != S_OK) - return ieHRESULT("initializing Direct2D", hr); - - hr = initDrawText(); - if (hr != S_OK) - return ieHRESULT("initializing DirectWrite", hr); - - if (registerAreaClass(hDefaultIcon, hDefaultCursor) == 0) - return ieLastErr("registering uiArea window class"); - - if (registerMessageFilter() == 0) - return ieLastErr("registering libui message filter"); - - if (registerD2DScratchClass(hDefaultIcon, hDefaultCursor) == 0) - return ieLastErr("initializing D2D scratch window class"); - - return NULL; -} - -void uiUninit(void) -{ - uninitMenus(); - unregisterD2DScratchClass(); - unregisterMessageFilter(); - unregisterArea(); - uninitDrawText(); - uninitDraw(); - CoUninitialize(); - if (DeleteObject(hollowBrush) == 0) - logLastError(L"error freeing hollow brush"); - uninitContainer(); - if (DeleteObject(hMessageFont) == 0) - logLastError(L"error deleting control font"); - unregisterWindowClass(); - // no need to delete the default icon or cursor; see http://stackoverflow.com/questions/30603077/ - uninitUtilWindow(); - uninitAlloc(); -} - -void uiFreeInitError(const char *err) -{ - if (*(err - 1) == '-') - uiFree((void *) (err - 1)); -} - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - if (fdwReason == DLL_PROCESS_ATTACH) - hInstance = hinstDLL; - return TRUE; -} diff --git a/deps/libui/windows/label.cpp b/deps/libui/windows/label.cpp deleted file mode 100644 index d74b7d183f..0000000000 --- a/deps/libui/windows/label.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// 11 april 2015 -#include "uipriv_windows.hpp" - -struct uiLabel { - uiWindowsControl c; - HWND hwnd; -}; - -uiWindowsControlAllDefaults(uiLabel) - -// via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define labelHeight 8 - -static void uiLabelMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiLabel *l = uiLabel(c); - uiWindowsSizing sizing; - int y; - - *width = uiWindowsWindowTextWidth(l->hwnd); - y = labelHeight; - uiWindowsGetSizing(l->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &y); - *height = y; -} - -char *uiLabelText(uiLabel *l) -{ - return uiWindowsWindowText(l->hwnd); -} - -void uiLabelSetText(uiLabel *l, const char *text) -{ - uiWindowsSetWindowText(l->hwnd, text); - // changing the text might necessitate a change in the label's size - uiWindowsControlMinimumSizeChanged(uiWindowsControl(l)); -} - -uiLabel *uiNewLabel(const char *text) -{ - uiLabel *l; - WCHAR *wtext; - - uiWindowsNewControl(uiLabel, l); - - wtext = toUTF16(text); - l->hwnd = uiWindowsEnsureCreateControlHWND(0, - L"static", wtext, - // SS_LEFTNOWORDWRAP clips text past the end; SS_NOPREFIX avoids accelerator translation - // controls are vertically aligned to the top by default (thanks Xeek in irc.freenode.net/#winapi) - SS_LEFTNOWORDWRAP | SS_NOPREFIX, - hInstance, NULL, - TRUE); - uiFree(wtext); - - return l; -} diff --git a/deps/libui/windows/libui.manifest b/deps/libui/windows/libui.manifest deleted file mode 100644 index 8beb6cfc89..0000000000 --- a/deps/libui/windows/libui.manifest +++ /dev/null @@ -1,31 +0,0 @@ - - - -Your application description here. - - - - - - - - - - - - - - - diff --git a/deps/libui/windows/main.cpp b/deps/libui/windows/main.cpp deleted file mode 100644 index eb6d84921d..0000000000 --- a/deps/libui/windows/main.cpp +++ /dev/null @@ -1,130 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.hpp" - -static HHOOK filter; - -static LRESULT CALLBACK filterProc(int code, WPARAM wParam, LPARAM lParam) -{ - MSG *msg = (MSG *) lParam; - - if (code < 0) - goto callNext; - - if (areaFilter(msg)) // don't continue to our IsDialogMessage() hack if the area handled it - goto discard; - - // TODO IsDialogMessage() hack here - - // otherwise keep going - goto callNext; - -discard: - // we handled it; discard the message so the dialog manager doesn't see it - return 1; - -callNext: - return CallNextHookEx(filter, code, wParam, lParam); -} - -int registerMessageFilter(void) -{ - filter = SetWindowsHookExW(WH_MSGFILTER, - filterProc, - hInstance, - GetCurrentThreadId()); - return filter != NULL; -} - -void unregisterMessageFilter(void) -{ - if (UnhookWindowsHookEx(filter) == 0) - logLastError(L"error unregistering libui message filter"); -} - -// LONGTERM http://blogs.msdn.com/b/oldnewthing/archive/2005/04/08/406509.aspx when adding accelerators, TranslateAccelerators() before IsDialogMessage() - -static void processMessage(MSG *msg) -{ - HWND correctParent; - - if (msg->hwnd != NULL) - correctParent = parentToplevel(msg->hwnd); - else // just to be safe - correctParent = GetActiveWindow(); - if (correctParent != NULL) - // this calls our mesage filter above for us - if (IsDialogMessage(correctParent, msg) != 0) - return; - TranslateMessage(msg); - DispatchMessageW(msg); -} - -static int waitMessage(MSG *msg) -{ - int res; - - res = GetMessageW(msg, NULL, 0, 0); - if (res < 0) { - logLastError(L"error calling GetMessage()"); - return 0; // bail out on error - } - return res != 0; // returns false on WM_QUIT -} - -void uiMain(void) -{ - while (uiMainStep(1)) - ; -} - -void uiMainSteps(void) -{ - // don't need to do anything here -} - -static int peekMessage(MSG *msg) -{ - BOOL res; - - res = PeekMessageW(msg, NULL, 0, 0, PM_REMOVE); - if (res == 0) - return 2; // no message available - if (msg->message != WM_QUIT) - return 1; // a message - return 0; // WM_QUIT -} - -int uiMainStep(int wait) -{ - MSG msg; - - if (wait) { - if (!waitMessage(&msg)) - return 0; - processMessage(&msg); - return 1; - } - - // don't wait for a message - switch (peekMessage(&msg)) { - case 0: // quit - // TODO PostQuitMessage() again? - return 0; - case 1: // process a message - processMessage(&msg); - // fall out to the case for no message - } - return 1; // no message -} - -void uiQuit(void) -{ - PostQuitMessage(0); -} - -void uiQueueMain(void (*f)(void *data), void *data) -{ - if (PostMessageW(utilWindow, msgQueued, (WPARAM) f, (LPARAM) data) == 0) - // LONGTERM this is likely not safe to call across threads (allocates memory) - logLastError(L"error queueing function to run on main thread"); -} diff --git a/deps/libui/windows/menu.cpp b/deps/libui/windows/menu.cpp deleted file mode 100644 index 6112fc13b1..0000000000 --- a/deps/libui/windows/menu.cpp +++ /dev/null @@ -1,369 +0,0 @@ -// 24 april 2015 -#include "uipriv_windows.hpp" - -// LONGTERM migrate to std::vector - -static uiMenu **menus = NULL; -static size_t len = 0; -static size_t cap = 0; -static BOOL menusFinalized = FALSE; -static WORD curID = 100; // start somewhere safe -static BOOL hasQuit = FALSE; -static BOOL hasPreferences = FALSE; -static BOOL hasAbout = FALSE; - -struct uiMenu { - WCHAR *name; - uiMenuItem **items; - size_t len; - size_t cap; -}; - -struct uiMenuItem { - WCHAR *name; - int type; - WORD id; - void (*onClicked)(uiMenuItem *, uiWindow *, void *); - void *onClickedData; - BOOL disabled; // template for new instances; kept in sync with everything else - BOOL checked; - HMENU *hmenus; - size_t len; - size_t cap; -}; - -enum { - typeRegular, - typeCheckbox, - typeQuit, - typePreferences, - typeAbout, - typeSeparator, -}; - -#define grow 32 - -static void sync(uiMenuItem *item) -{ - size_t i; - MENUITEMINFOW mi; - - ZeroMemory(&mi, sizeof (MENUITEMINFOW)); - mi.cbSize = sizeof (MENUITEMINFOW); - mi.fMask = MIIM_STATE; - if (item->disabled) - mi.fState |= MFS_DISABLED; - if (item->checked) - mi.fState |= MFS_CHECKED; - - for (i = 0; i < item->len; i++) - if (SetMenuItemInfo(item->hmenus[i], item->id, FALSE, &mi) == 0) - logLastError(L"error synchronizing menu items"); -} - -static void defaultOnClicked(uiMenuItem *item, uiWindow *w, void *data) -{ - // do nothing -} - -static void onQuitClicked(uiMenuItem *item, uiWindow *w, void *data) -{ - if (shouldQuit()) - uiQuit(); -} - -void uiMenuItemEnable(uiMenuItem *i) -{ - i->disabled = FALSE; - sync(i); -} - -void uiMenuItemDisable(uiMenuItem *i) -{ - i->disabled = TRUE; - sync(i); -} - -void uiMenuItemOnClicked(uiMenuItem *i, void (*f)(uiMenuItem *, uiWindow *, void *), void *data) -{ - if (i->type == typeQuit) - userbug("You can not call uiMenuItemOnClicked() on a Quit item; use uiOnShouldQuit() instead."); - i->onClicked = f; - i->onClickedData = data; -} - -int uiMenuItemChecked(uiMenuItem *i) -{ - return i->checked != FALSE; -} - -void uiMenuItemSetChecked(uiMenuItem *i, int checked) -{ - // use explicit values - i->checked = FALSE; - if (checked) - i->checked = TRUE; - sync(i); -} - -static uiMenuItem *newItem(uiMenu *m, int type, const char *name) -{ - uiMenuItem *item; - - if (menusFinalized) - userbug("You can not create a new menu item after menus have been finalized."); - - if (m->len >= m->cap) { - m->cap += grow; - m->items = (uiMenuItem **) uiRealloc(m->items, m->cap * sizeof (uiMenuItem *), "uiMenuitem *[]"); - } - - item = uiNew(uiMenuItem); - - m->items[m->len] = item; - m->len++; - - item->type = type; - switch (item->type) { - case typeQuit: - item->name = toUTF16("Quit"); - break; - case typePreferences: - item->name = toUTF16("Preferences..."); - break; - case typeAbout: - item->name = toUTF16("About"); - break; - case typeSeparator: - break; - default: - item->name = toUTF16(name); - break; - } - - if (item->type != typeSeparator) { - item->id = curID; - curID++; - } - - if (item->type == typeQuit) { - // can't call uiMenuItemOnClicked() here - item->onClicked = onQuitClicked; - item->onClickedData = NULL; - } else - uiMenuItemOnClicked(item, defaultOnClicked, NULL); - - return item; -} - -uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name) -{ - return newItem(m, typeRegular, name); -} - -uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name) -{ - return newItem(m, typeCheckbox, name); -} - -uiMenuItem *uiMenuAppendQuitItem(uiMenu *m) -{ - if (hasQuit) - userbug("You can not have multiple Quit menu items in a program."); - hasQuit = TRUE; - newItem(m, typeSeparator, NULL); - return newItem(m, typeQuit, NULL); -} - -uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m) -{ - if (hasPreferences) - userbug("You can not have multiple Preferences menu items in a program."); - hasPreferences = TRUE; - newItem(m, typeSeparator, NULL); - return newItem(m, typePreferences, NULL); -} - -uiMenuItem *uiMenuAppendAboutItem(uiMenu *m) -{ - if (hasAbout) - // TODO place these userbug strings in a header - userbug("You can not have multiple About menu items in a program."); - hasAbout = TRUE; - newItem(m, typeSeparator, NULL); - return newItem(m, typeAbout, NULL); -} - -void uiMenuAppendSeparator(uiMenu *m) -{ - newItem(m, typeSeparator, NULL); -} - -uiMenu *uiNewMenu(const char *name) -{ - uiMenu *m; - - if (menusFinalized) - userbug("You can not create a new menu after menus have been finalized."); - if (len >= cap) { - cap += grow; - menus = (uiMenu **) uiRealloc(menus, cap * sizeof (uiMenu *), "uiMenu *[]"); - } - - m = uiNew(uiMenu); - - menus[len] = m; - len++; - - m->name = toUTF16(name); - - return m; -} - -static void appendMenuItem(HMENU menu, uiMenuItem *item) -{ - UINT uFlags; - - uFlags = MF_SEPARATOR; - if (item->type != typeSeparator) { - uFlags = MF_STRING; - if (item->disabled) - uFlags |= MF_DISABLED | MF_GRAYED; - if (item->checked) - uFlags |= MF_CHECKED; - } - if (AppendMenuW(menu, uFlags, item->id, item->name) == 0) - logLastError(L"error appending menu item"); - - if (item->len >= item->cap) { - item->cap += grow; - item->hmenus = (HMENU *) uiRealloc(item->hmenus, item->cap * sizeof (HMENU), "HMENU[]"); - } - item->hmenus[item->len] = menu; - item->len++; -} - -static HMENU makeMenu(uiMenu *m) -{ - HMENU menu; - size_t i; - - menu = CreatePopupMenu(); - if (menu == NULL) - logLastError(L"error creating menu"); - for (i = 0; i < m->len; i++) - appendMenuItem(menu, m->items[i]); - return menu; -} - -HMENU makeMenubar(void) -{ - HMENU menubar; - HMENU menu; - size_t i; - - menusFinalized = TRUE; - - menubar = CreateMenu(); - if (menubar == NULL) - logLastError(L"error creating menubar"); - - for (i = 0; i < len; i++) { - menu = makeMenu(menus[i]); - if (AppendMenuW(menubar, MF_POPUP | MF_STRING, (UINT_PTR) menu, menus[i]->name) == 0) - logLastError(L"error appending menu to menubar"); - } - - return menubar; -} - -void runMenuEvent(WORD id, uiWindow *w) -{ - uiMenu *m; - uiMenuItem *item; - size_t i, j; - - // this isn't optimal, but it works, and it should be just fine for most cases - for (i = 0; i < len; i++) { - m = menus[i]; - for (j = 0; j < m->len; j++) { - item = m->items[j]; - if (item->id == id) - goto found; - } - } - // no match - implbug("unknown menu ID %hu in runMenuEvent()", id); - -found: - // first toggle checkboxes, if any - if (item->type == typeCheckbox) - uiMenuItemSetChecked(item, !uiMenuItemChecked(item)); - - // then run the event - (*(item->onClicked))(item, w, item->onClickedData); -} - -static void freeMenu(uiMenu *m, HMENU submenu) -{ - size_t i; - uiMenuItem *item; - size_t j; - - for (i = 0; i < m->len; i++) { - item = m->items[i]; - for (j = 0; j < item->len; j++) - if (item->hmenus[j] == submenu) - break; - if (j >= item->len) - implbug("submenu handle %p not found in freeMenu()", submenu); - for (; j < item->len - 1; j++) - item->hmenus[j] = item->hmenus[j + 1]; - item->hmenus[j] = NULL; - item->len--; - } -} - -void freeMenubar(HMENU menubar) -{ - size_t i; - MENUITEMINFOW mi; - - for (i = 0; i < len; i++) { - ZeroMemory(&mi, sizeof (MENUITEMINFOW)); - mi.cbSize = sizeof (MENUITEMINFOW); - mi.fMask = MIIM_SUBMENU; - if (GetMenuItemInfoW(menubar, i, TRUE, &mi) == 0) - logLastError(L"error getting menu to delete item references from"); - freeMenu(menus[i], mi.hSubMenu); - } - // no need to worry about destroying any menus; destruction of the window they're in will do it for us -} - -void uninitMenus(void) -{ - uiMenu *m; - uiMenuItem *item; - size_t i, j; - - for (i = 0; i < len; i++) { - m = menus[i]; - uiFree(m->name); - for (j = 0; j < m->len; j++) { - item = m->items[j]; - if (item->len != 0) - // LONGTERM userbug()? - implbug("menu item %p (%ws) still has uiWindows attached; did you forget to destroy some windows?", item, item->name); - if (item->name != NULL) - uiFree(item->name); - if (item->hmenus != NULL) - uiFree(item->hmenus); - uiFree(item); - } - if (m->items != NULL) - uiFree(m->items); - uiFree(m); - } - if (menus != NULL) - uiFree(menus); -} diff --git a/deps/libui/windows/multilineentry.cpp b/deps/libui/windows/multilineentry.cpp deleted file mode 100644 index a32960cb8a..0000000000 --- a/deps/libui/windows/multilineentry.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// 8 april 2015 -#include "uipriv_windows.hpp" - -// TODO there's alpha darkening of text going on in read-only ones; something is up in our parent logic - -struct uiMultilineEntry { - uiWindowsControl c; - HWND hwnd; - void (*onChanged)(uiMultilineEntry *, void *); - void *onChangedData; - BOOL inhibitChanged; -}; - -static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult) -{ - uiMultilineEntry *e = uiMultilineEntry(c); - - if (code != EN_CHANGE) - return FALSE; - if (e->inhibitChanged) - return FALSE; - (*(e->onChanged))(e, e->onChangedData); - *lResult = 0; - return TRUE; -} - -static void uiMultilineEntryDestroy(uiControl *c) -{ - uiMultilineEntry *e = uiMultilineEntry(c); - - uiWindowsUnregisterWM_COMMANDHandler(e->hwnd); - uiWindowsEnsureDestroyWindow(e->hwnd); - uiFreeControl(uiControl(e)); -} - -uiWindowsControlAllDefaultsExceptDestroy(uiMultilineEntry) - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define entryWidth 107 /* this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary */ -// LONGTERM change this for multiline text boxes (longterm because how?) -#define entryHeight 14 - -static void uiMultilineEntryMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiMultilineEntry *e = uiMultilineEntry(c); - uiWindowsSizing sizing; - int x, y; - - x = entryWidth; - y = entryHeight; - uiWindowsGetSizing(e->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - *width = x; - *height = y; -} - -static void defaultOnChanged(uiMultilineEntry *e, void *data) -{ - // do nothing -} - -char *uiMultilineEntryText(uiMultilineEntry *e) -{ - char *out; - - out = uiWindowsWindowText(e->hwnd); - CRLFtoLF(out); - return out; -} - -void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text) -{ - char *crlf; - - // doing this raises an EN_CHANGED - e->inhibitChanged = TRUE; - crlf = LFtoCRLF(text); - uiWindowsSetWindowText(e->hwnd, text); - uiFree(crlf); - e->inhibitChanged = FALSE; - // don't queue the control for resize; entry sizes are independent of their contents -} - -void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text) -{ - LRESULT n; - char *crlf; - WCHAR *wtext; - - // doing this raises an EN_CHANGED - e->inhibitChanged = TRUE; - // TODO preserve selection? caret? what if caret used to be at end? - // TODO scroll to bottom? - n = SendMessageW(e->hwnd, WM_GETTEXTLENGTH, 0, 0); - SendMessageW(e->hwnd, EM_SETSEL, n, n); - crlf = LFtoCRLF(text); - wtext = toUTF16(crlf); - uiFree(crlf); - SendMessageW(e->hwnd, EM_REPLACESEL, FALSE, (LPARAM) wtext); - uiFree(wtext); - e->inhibitChanged = FALSE; -} - -void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *, void *), void *data) -{ - e->onChanged = f; - e->onChangedData = data; -} - -int uiMultilineEntryReadOnly(uiMultilineEntry *e) -{ - return (getStyle(e->hwnd) & ES_READONLY) != 0; -} - -void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly) -{ - WPARAM ro; - - ro = (WPARAM) FALSE; - if (readonly) - ro = (WPARAM) TRUE; - if (SendMessage(e->hwnd, EM_SETREADONLY, ro, 0) == 0) - logLastError(L"error making uiMultilineEntry read-only"); -} - -static uiMultilineEntry *finishMultilineEntry(DWORD style) -{ - uiMultilineEntry *e; - - uiWindowsNewControl(uiMultilineEntry, e); - - e->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE, - L"edit", L"", - ES_AUTOVSCROLL | ES_LEFT | ES_MULTILINE | ES_NOHIDESEL | ES_WANTRETURN | WS_TABSTOP | WS_VSCROLL | style, - hInstance, NULL, - TRUE); - - uiWindowsRegisterWM_COMMANDHandler(e->hwnd, onWM_COMMAND, uiControl(e)); - uiMultilineEntryOnChanged(e, defaultOnChanged, NULL); - - return e; -} - -uiMultilineEntry *uiNewMultilineEntry(void) -{ - return finishMultilineEntry(0); -} - -uiMultilineEntry *uiNewNonWrappingMultilineEntry(void) -{ - return finishMultilineEntry(WS_HSCROLL | ES_AUTOHSCROLL); -} diff --git a/deps/libui/windows/notes b/deps/libui/windows/notes deleted file mode 100644 index f554dd282d..0000000000 --- a/deps/libui/windows/notes +++ /dev/null @@ -1,3 +0,0 @@ -DIALOGS -do not accelerate OK and Cancel buttons in dialogs - http://blogs.msdn.com/b/oldnewthing/archive/2008/05/08/8467905.aspx diff --git a/deps/libui/windows/parent.cpp b/deps/libui/windows/parent.cpp deleted file mode 100644 index bde6fb94e4..0000000000 --- a/deps/libui/windows/parent.cpp +++ /dev/null @@ -1,144 +0,0 @@ -// 26 april 2015 -#include "uipriv_windows.hpp" - -// This contains code used by all uiControls that contain other controls. -// It also contains the code to draw the background of a container.c container, as that is a variant of the WM_CTLCOLORxxx handler code. - -static HBRUSH parentBrush = NULL; - -static HWND parentWithBackground(HWND hwnd) -{ - HWND parent; - int cls; - - parent = hwnd; - for (;;) { - parent = parentOf(parent); - // skip groupboxes; they're (supposed to be) transparent - // skip uiContainers; they don't draw anything - cls = windowClassOf(parent, L"button", containerClass, NULL); - if (cls != 0 && cls != 1) - break; - } - return parent; -} - -struct parentDraw { - HDC cdc; - HBITMAP bitmap; - HBITMAP prevbitmap; -}; - -static HRESULT parentDraw(HDC dc, HWND parent, struct parentDraw *pd) -{ - RECT r; - - uiWindowsEnsureGetClientRect(parent, &r); - pd->cdc = CreateCompatibleDC(dc); - if (pd->cdc == NULL) - return logLastError(L"error creating compatible DC"); - pd->bitmap = CreateCompatibleBitmap(dc, r.right - r.left, r.bottom - r.top); - if (pd->bitmap == NULL) - return logLastError(L"error creating compatible bitmap"); - pd->prevbitmap = (HBITMAP) SelectObject(pd->cdc, pd->bitmap); - if (pd->prevbitmap == NULL) - return logLastError(L"error selecting bitmap into compatible DC"); - SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) (pd->cdc), PRF_CLIENT); - return S_OK; -} - -static void endParentDraw(struct parentDraw *pd) -{ - // continue in case of any error - if (pd->prevbitmap != NULL) - if (((HBITMAP) SelectObject(pd->cdc, pd->prevbitmap)) != pd->bitmap) - logLastError(L"error selecting previous bitmap back into compatible DC"); - if (pd->bitmap != NULL) - if (DeleteObject(pd->bitmap) == 0) - logLastError(L"error deleting compatible bitmap"); - if (pd->cdc != NULL) - if (DeleteDC(pd->cdc) == 0) - logLastError(L"error deleting compatible DC"); -} - -// see http://www.codeproject.com/Articles/5978/Correctly-drawn-themed-dialogs-in-WinXP -static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc) -{ - HWND parent; - RECT hwndScreenRect; - struct parentDraw pd; - HBRUSH brush; - HRESULT hr; - - parent = parentWithBackground(hwnd); - - hr = parentDraw(dc, parent, &pd); - if (hr != S_OK) - return NULL; - brush = CreatePatternBrush(pd.bitmap); - if (brush == NULL) { - logLastError(L"error creating pattern brush"); - endParentDraw(&pd); - return NULL; - } - endParentDraw(&pd); - - // now figure out where the control is relative to the parent so we can align the brush properly - // if anything fails, give up and return the brush as-is - uiWindowsEnsureGetWindowRect(hwnd, &hwndScreenRect); - // this will be in screen coordinates; convert to parent coordinates - mapWindowRect(NULL, parent, &hwndScreenRect); - if (SetBrushOrgEx(dc, -hwndScreenRect.left, -hwndScreenRect.top, NULL) == 0) - logLastError(L"error setting brush origin"); - - return brush; -} - -void paintContainerBackground(HWND hwnd, HDC dc, RECT *paintRect) -{ - HWND parent; - RECT paintRectParent; - struct parentDraw pd; - HRESULT hr; - - parent = parentWithBackground(hwnd); - hr = parentDraw(dc, parent, &pd); - if (hr != S_OK) // we couldn't get it; draw nothing - return; - - paintRectParent = *paintRect; - mapWindowRect(hwnd, parent, &paintRectParent); - if (BitBlt(dc, paintRect->left, paintRect->top, paintRect->right - paintRect->left, paintRect->bottom - paintRect->top, - pd.cdc, paintRectParent.left, paintRectParent.top, - SRCCOPY) == 0) - logLastError(L"error drawing parent background over uiContainer"); - - endParentDraw(&pd); -} - -// TODO make this public if we want custom containers -// why have this to begin with? http://blogs.msdn.com/b/oldnewthing/archive/2010/03/16/9979112.aspx -BOOL handleParentMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult) -{ - switch (uMsg) { - case WM_COMMAND: - return runWM_COMMAND(wParam, lParam, lResult); - case WM_NOTIFY: - return runWM_NOTIFY(wParam, lParam, lResult); - case WM_HSCROLL: - return runWM_HSCROLL(wParam, lParam, lResult); - case WM_CTLCOLORSTATIC: - case WM_CTLCOLORBTN: - if (parentBrush != NULL) - if (DeleteObject(parentBrush) == 0) - logLastError(L"error deleting old background brush()"); // but continue anyway; we will leak a brush but whatever - if (SetBkMode((HDC) wParam, TRANSPARENT) == 0) - logLastError(L"error setting transparent background mode to controls"); // but continue anyway; text will be wrong - parentBrush = getControlBackgroundBrush((HWND) lParam, (HDC) wParam); - if (parentBrush == NULL) // failed; just do default behavior - return FALSE; - *lResult = (LRESULT) parentBrush; - return TRUE; - } - return FALSE; -} diff --git a/deps/libui/windows/progressbar.cpp b/deps/libui/windows/progressbar.cpp deleted file mode 100644 index 3750eb6aee..0000000000 --- a/deps/libui/windows/progressbar.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// 19 may 2015 -#include "uipriv_windows.hpp" - -struct uiProgressBar { - uiWindowsControl c; - HWND hwnd; -}; - -uiWindowsControlAllDefaults(uiProgressBar) - -// via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define pbarWidth 237 -#define pbarHeight 8 - -static void uiProgressBarMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiProgressBar *p = uiProgressBar(c); - uiWindowsSizing sizing; - int x, y; - - x = pbarWidth; - y = pbarHeight; - uiWindowsGetSizing(p->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - *width = x; - *height = y; -} - -#define indeterminate(p) ((getStyle(p->hwnd) & PBS_MARQUEE) != 0) - -int uiProgressBarValue(uiProgressBar *p) -{ - if (indeterminate(p)) - return -1; - return SendMessage(p->hwnd, PBM_GETPOS, 0, 0); -} - -// unfortunately, as of Vista progress bars have a forced animation on increase -// we have to set the progress bar to value + 1 and decrease it back to value if we want an "instant" change -// see http://stackoverflow.com/questions/2217688/windows-7-aero-theme-progress-bar-bug -// it's not ideal/perfect, but it will have to do -void uiProgressBarSetValue(uiProgressBar *p, int value) -{ - if (value == -1) { - if (!indeterminate(p)) { - setStyle(p->hwnd, getStyle(p->hwnd) | PBS_MARQUEE); - SendMessageW(p->hwnd, PBM_SETMARQUEE, (WPARAM) TRUE, 0); - } - return; - } - if (indeterminate(p)) { - SendMessageW(p->hwnd, PBM_SETMARQUEE, (WPARAM) FALSE, 0); - setStyle(p->hwnd, getStyle(p->hwnd) & ~PBS_MARQUEE); - } - - if (value < 0 || value > 100) - userbug("Value %d is out of range for uiProgressBars.", value); - - if (value == 100) { // because we can't 101 - SendMessageW(p->hwnd, PBM_SETRANGE32, 0, 101); - SendMessageW(p->hwnd, PBM_SETPOS, 101, 0); - SendMessageW(p->hwnd, PBM_SETPOS, 100, 0); - SendMessageW(p->hwnd, PBM_SETRANGE32, 0, 100); - return; - } - SendMessageW(p->hwnd, PBM_SETPOS, (WPARAM) (value + 1), 0); - SendMessageW(p->hwnd, PBM_SETPOS, (WPARAM) value, 0); -} - -uiProgressBar *uiNewProgressBar(void) -{ - uiProgressBar *p; - - uiWindowsNewControl(uiProgressBar, p); - - p->hwnd = uiWindowsEnsureCreateControlHWND(0, - PROGRESS_CLASSW, L"", - PBS_SMOOTH, - hInstance, NULL, - FALSE); - - return p; -} diff --git a/deps/libui/windows/radiobuttons.cpp b/deps/libui/windows/radiobuttons.cpp deleted file mode 100644 index 29cd2e6611..0000000000 --- a/deps/libui/windows/radiobuttons.cpp +++ /dev/null @@ -1,196 +0,0 @@ -// 20 may 2015 -#include "uipriv_windows.hpp" - -// desired behavior: -// - tab moves between the radio buttons and the adjacent controls -// - arrow keys navigate between radio buttons -// - arrow keys do not leave the radio buttons (this is done in control.c) -// - arrow keys wrap around bare groups (if the previous control has WS_GROUP but the first radio button doesn't, then it doesn't; since our radio buttons are all in their own child window we can't do that) -// - clicking on a radio button draws a focus rect (TODO) - -struct uiRadioButtons { - uiWindowsControl c; - HWND hwnd; // of the container - std::vector *hwnds; // of the buttons - void (*onSelected)(uiRadioButtons *, void *); - void *onSelectedData; -}; - -static BOOL onWM_COMMAND(uiControl *c, HWND clicked, WORD code, LRESULT *lResult) -{ - uiRadioButtons *r = uiRadioButtons(c); - WPARAM check; - - if (code != BN_CLICKED) - return FALSE; - for (const HWND &hwnd : *(r->hwnds)) { - check = BST_UNCHECKED; - if (clicked == hwnd) - check = BST_CHECKED; - SendMessage(hwnd, BM_SETCHECK, check, 0); - } - (*(r->onSelected))(r, r->onSelectedData); - *lResult = 0; - return TRUE; -} - -static void defaultOnSelected(uiRadioButtons *r, void *data) -{ - // do nothing -} - -static void uiRadioButtonsDestroy(uiControl *c) -{ - uiRadioButtons *r = uiRadioButtons(c); - - for (const HWND &hwnd : *(r->hwnds)) { - uiWindowsUnregisterWM_COMMANDHandler(hwnd); - uiWindowsEnsureDestroyWindow(hwnd); - } - delete r->hwnds; - uiWindowsEnsureDestroyWindow(r->hwnd); - uiFreeControl(uiControl(r)); -} - -// TODO SyncEnableState -uiWindowsControlAllDefaultsExceptDestroy(uiRadioButtons) - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define radiobuttonHeight 10 -// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx -#define radiobuttonXFromLeftOfBoxToLeftOfLabel 12 - -static void uiRadioButtonsMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiRadioButtons *r = uiRadioButtons(c); - int wid, maxwid; - uiWindowsSizing sizing; - int x, y; - - if (r->hwnds->size() == 0) { - *width = 0; - *height = 0; - return; - } - maxwid = 0; - for (const HWND &hwnd : *(r->hwnds)) { - wid = uiWindowsWindowTextWidth(hwnd); - if (maxwid < wid) - maxwid = wid; - } - - x = radiobuttonXFromLeftOfBoxToLeftOfLabel; - y = radiobuttonHeight; - uiWindowsGetSizing((*(r->hwnds))[0], &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - - *width = x + maxwid; - *height = y * r->hwnds->size(); -} - -static void radiobuttonsRelayout(uiRadioButtons *r) -{ - RECT client; - int x, y, width, height; - int height1; - uiWindowsSizing sizing; - - if (r->hwnds->size() == 0) - return; - uiWindowsEnsureGetClientRect(r->hwnd, &client); - x = client.left; - y = client.top; - width = client.right - client.left; - height1 = radiobuttonHeight; - uiWindowsGetSizing((*(r->hwnds))[0], &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &height1); - height = height1; - for (const HWND &hwnd : *(r->hwnds)) { - uiWindowsEnsureMoveWindowDuringResize(hwnd, x, y, width, height); - y += height; - } -} - -static void radiobuttonsArrangeChildren(uiRadioButtons *r) -{ - LONG_PTR controlID; - HWND insertAfter; - - controlID = 100; - insertAfter = NULL; - for (const HWND &hwnd : *(r->hwnds)) - uiWindowsEnsureAssignControlIDZOrder(hwnd, &controlID, &insertAfter); -} - -void uiRadioButtonsAppend(uiRadioButtons *r, const char *text) -{ - HWND hwnd; - WCHAR *wtext; - DWORD groupTabStop; - - // the first radio button gets both WS_GROUP and WS_TABSTOP - // successive radio buttons get *neither* - groupTabStop = 0; - if (r->hwnds->size() == 0) - groupTabStop = WS_GROUP | WS_TABSTOP; - - wtext = toUTF16(text); - hwnd = uiWindowsEnsureCreateControlHWND(0, - L"button", wtext, - BS_RADIOBUTTON | groupTabStop, - hInstance, NULL, - TRUE); - uiFree(wtext); - uiWindowsEnsureSetParentHWND(hwnd, r->hwnd); - uiWindowsRegisterWM_COMMANDHandler(hwnd, onWM_COMMAND, uiControl(r)); - r->hwnds->push_back(hwnd); - radiobuttonsArrangeChildren(r); - uiWindowsControlMinimumSizeChanged(uiWindowsControl(r)); -} - -int uiRadioButtonsSelected(uiRadioButtons *r) -{ - size_t i; - - for (i = 0; i < r->hwnds->size(); i++) - if (SendMessage((*(r->hwnds))[i], BM_GETCHECK, 0, 0) == BST_CHECKED) - return i; - return -1; -} - -void uiRadioButtonsSetSelected(uiRadioButtons *r, int n) -{ - int m; - - m = uiRadioButtonsSelected(r); - if (m != -1) - SendMessage((*(r->hwnds))[m], BM_SETCHECK, BST_UNCHECKED, 0); - if (n != -1) - SendMessage((*(r->hwnds))[n], BM_SETCHECK, BST_CHECKED, 0); -} - -void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data) -{ - r->onSelected = f; - r->onSelectedData = data; -} - -static void onResize(uiWindowsControl *c) -{ - radiobuttonsRelayout(uiRadioButtons(c)); -} - -uiRadioButtons *uiNewRadioButtons(void) -{ - uiRadioButtons *r; - - uiWindowsNewControl(uiRadioButtons, r); - - r->hwnd = uiWindowsMakeContainer(uiWindowsControl(r), onResize); - - r->hwnds = new std::vector; - - uiRadioButtonsOnSelected(r, defaultOnSelected, NULL); - - return r; -} diff --git a/deps/libui/windows/resources.hpp b/deps/libui/windows/resources.hpp deleted file mode 100644 index 4ae547255c..0000000000 --- a/deps/libui/windows/resources.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// 30 may 2015 - -#define rcTabPageDialog 29000 -#define rcFontDialog 29001 -#define rcColorDialog 29002 - -// TODO normalize these - -#define rcFontFamilyCombobox 1000 -#define rcFontStyleCombobox 1001 -#define rcFontSizeCombobox 1002 -#define rcFontSamplePlacement 1003 - -#define rcColorSVChooser 1100 -#define rcColorHSlider 1101 -#define rcPreview 1102 -#define rcOpacitySlider 1103 -#define rcH 1104 -#define rcS 1105 -#define rcV 1106 -#define rcRDouble 1107 -#define rcRInt 1108 -#define rcGDouble 1109 -#define rcGInt 1110 -#define rcBDouble 1111 -#define rcBInt 1112 -#define rcADouble 1113 -#define rcAInt 1114 -#define rcHex 1115 -#define rcHLabel 1116 -#define rcSLabel 1117 -#define rcVLabel 1118 -#define rcRLabel 1119 -#define rcGLabel 1120 -#define rcBLabel 1121 -#define rcALabel 1122 -#define rcHexLabel 1123 diff --git a/deps/libui/windows/resources.rc b/deps/libui/windows/resources.rc deleted file mode 100644 index 989dfc9147..0000000000 --- a/deps/libui/windows/resources.rc +++ /dev/null @@ -1,96 +0,0 @@ -// 30 may 2015 -#include "winapi.hpp" -#include "resources.hpp" - -// this is a UTF-8 file -#pragma code_page(65001) - -// this is the Common Controls 6 manifest -// we only define it in a shared build; static builds have to include the appropriate parts of the manifest in the output executable -// LONGTERM set up the string values here -#ifndef _UI_STATIC -ISOLATIONAWARE_MANIFEST_RESOURCE_ID RT_MANIFEST "libui.manifest" -#endif - -// this is the dialog template used by tab pages; see windows/tabpage.c for details -rcTabPageDialog DIALOGEX 0, 0, 100, 100 -STYLE DS_CONTROL | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -BEGIN - // nothing -END - -// this is for our custom DirectWrite-based font dialog (see fontdialog.cpp) -// this is based on the "New Font Dialog with Syslink" in Microsoft's font.dlg -// LONGTERM look at localization -// LONGTERM make it look tighter and nicer like the real one, including the actual heights of the font family and style comboboxes -rcFontDialog DIALOGEX 13, 54, 243, 200 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_3DLOOK -CAPTION "Font" -FONT 9, "Segoe UI" -BEGIN - LTEXT "&Font:", -1, 7, 7, 98, 9 - COMBOBOX rcFontFamilyCombobox, 7, 16, 98, 76, - CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL | - CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS - - LTEXT "Font st&yle:", -1, 114, 7, 74, 9 - COMBOBOX rcFontStyleCombobox, 114, 16, 74, 76, - CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL | - WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS - - LTEXT "&Size:", -1, 198, 7, 36, 9 - COMBOBOX rcFontSizeCombobox, 198, 16, 36, 76, - CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL | - CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS - - GROUPBOX "Sample", -1, 7, 97, 227, 70, WS_GROUP - CTEXT "AaBbYyZz", rcFontSamplePlacement, 9, 106, 224, 60, SS_NOPREFIX | NOT WS_VISIBLE - - DEFPUSHBUTTON "OK", IDOK, 141, 181, 45, 14, WS_GROUP - PUSHBUTTON "Cancel", IDCANCEL, 190, 181, 45, 14, WS_GROUP -END - -rcColorDialog DIALOGEX 13, 54, 344, 209 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_3DLOOK -CAPTION "Color" -FONT 9, "Segoe UI" -BEGIN - // this size should be big enough to get at least 256x256 on font sizes >= 8 pt - CTEXT "AaBbYyZz", rcColorSVChooser, 7, 7, 195, 195, SS_NOPREFIX | SS_BLACKRECT - - // width is the suggested slider height since this is vertical - CTEXT "AaBbYyZz", rcColorHSlider, 206, 7, 15, 195, SS_NOPREFIX | SS_BLACKRECT - - LTEXT "Preview:", -1, 230, 7, 107, 9, SS_NOPREFIX - CTEXT "AaBbYyZz", rcPreview, 230, 16, 107, 20, SS_NOPREFIX | SS_BLACKRECT - - LTEXT "Opacity:", -1, 230, 45, 107, 9, SS_NOPREFIX - CTEXT "AaBbYyZz", rcOpacitySlider, 230, 54, 107, 15, SS_NOPREFIX | SS_BLACKRECT - - LTEXT "&H:", rcHLabel, 230, 81, 8, 8 - EDITTEXT rcH, 238, 78, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - LTEXT "&S:", rcSLabel, 230, 95, 8, 8 - EDITTEXT rcS, 238, 92, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - LTEXT "&V:", rcVLabel, 230, 109, 8, 8 - EDITTEXT rcV, 238, 106, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - - LTEXT "&R:", rcRLabel, 277, 81, 8, 8 - EDITTEXT rcRDouble, 285, 78, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - EDITTEXT rcRInt, 315, 78, 20, 14, ES_LEFT | ES_AUTOHSCROLL | ES_NUMBER | WS_TABSTOP, WS_EX_CLIENTEDGE - LTEXT "&G:", rcGLabel, 277, 95, 8, 8 - EDITTEXT rcGDouble, 285, 92, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - EDITTEXT rcGInt, 315, 92, 20, 14, ES_LEFT | ES_AUTOHSCROLL | ES_NUMBER | WS_TABSTOP, WS_EX_CLIENTEDGE - LTEXT "&B:", rcBLabel, 277, 109, 8, 8 - EDITTEXT rcBDouble, 285, 106, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - EDITTEXT rcBInt, 315, 106, 20, 14, ES_LEFT | ES_AUTOHSCROLL | ES_NUMBER | WS_TABSTOP, WS_EX_CLIENTEDGE - LTEXT "&A:", rcALabel, 277, 123, 8, 8 - EDITTEXT rcADouble, 285, 120, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - EDITTEXT rcAInt, 315, 120, 20, 14, ES_LEFT | ES_AUTOHSCROLL | ES_NUMBER | WS_TABSTOP, WS_EX_CLIENTEDGE - - LTEXT "He&x:", rcHexLabel, 269, 146, 16, 8 - EDITTEXT rcHex, 285, 143, 50, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - - DEFPUSHBUTTON "OK", IDOK, 243, 188, 45, 14, WS_GROUP - PUSHBUTTON "Cancel", IDCANCEL, 292, 188, 45, 14, WS_GROUP -END diff --git a/deps/libui/windows/separator.cpp b/deps/libui/windows/separator.cpp deleted file mode 100644 index e123e2756f..0000000000 --- a/deps/libui/windows/separator.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// 20 may 2015 -#include "uipriv_windows.hpp" - -// references: -// - http://stackoverflow.com/questions/2892703/how-do-i-draw-separators -// - https://msdn.microsoft.com/en-us/library/windows/desktop/dn742405%28v=vs.85%29.aspx - -struct uiSeparator { - uiWindowsControl c; - HWND hwnd; - BOOL vertical; -}; - -uiWindowsControlAllDefaults(uiSeparator) - -// via https://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx -#define separatorHeight 1 - -// TODO -#define separatorWidth 1 - -static void uiSeparatorMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiSeparator *s = uiSeparator(c); - uiWindowsSizing sizing; - int x, y; - - *width = 1; // TODO - *height = 1; - x = separatorWidth; - y = separatorHeight; - uiWindowsGetSizing(s->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - if (s->vertical) - *width = x; - else - *height = y; -} - -uiSeparator *uiNewHorizontalSeparator(void) -{ - uiSeparator *s; - - uiWindowsNewControl(uiSeparator, s); - - s->hwnd = uiWindowsEnsureCreateControlHWND(0, - L"static", L"", - SS_ETCHEDHORZ, - hInstance, NULL, - TRUE); - - return s; -} - -uiSeparator *uiNewVerticalSeparator(void) -{ - uiSeparator *s; - - uiWindowsNewControl(uiSeparator, s); - - s->hwnd = uiWindowsEnsureCreateControlHWND(0, - L"static", L"", - SS_ETCHEDHORZ, - hInstance, NULL, - TRUE); - s->vertical = TRUE; - - return s; -} diff --git a/deps/libui/windows/sizing.cpp b/deps/libui/windows/sizing.cpp deleted file mode 100644 index a6d25d6ef3..0000000000 --- a/deps/libui/windows/sizing.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// 14 may 2015 -#include "uipriv_windows.hpp" - -// TODO rework the error handling -void getSizing(HWND hwnd, uiWindowsSizing *sizing, HFONT font) -{ - HDC dc; - HFONT prevfont; - TEXTMETRICW tm; - SIZE size; - - dc = GetDC(hwnd); - if (dc == NULL) - logLastError(L"error getting DC"); - prevfont = (HFONT) SelectObject(dc, font); - if (prevfont == NULL) - logLastError(L"error loading control font into device context"); - - ZeroMemory(&tm, sizeof (TEXTMETRICW)); - if (GetTextMetricsW(dc, &tm) == 0) - logLastError(L"error getting text metrics"); - if (GetTextExtentPoint32W(dc, L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size) == 0) - logLastError(L"error getting text extent point"); - - sizing->BaseX = (int) ((size.cx / 26 + 1) / 2); - sizing->BaseY = (int) tm.tmHeight; - sizing->InternalLeading = tm.tmInternalLeading; - - if (SelectObject(dc, prevfont) != font) - logLastError(L"error restoring previous font into device context"); - if (ReleaseDC(hwnd, dc) == 0) - logLastError(L"error releasing DC"); -} - -void uiWindowsGetSizing(HWND hwnd, uiWindowsSizing *sizing) -{ - return getSizing(hwnd, sizing, hMessageFont); -} - -#define dlgUnitsToX(dlg, baseX) MulDiv((dlg), (baseX), 4) -#define dlgUnitsToY(dlg, baseY) MulDiv((dlg), (baseY), 8) - -void uiWindowsSizingDlgUnitsToPixels(uiWindowsSizing *sizing, int *x, int *y) -{ - if (x != NULL) - *x = dlgUnitsToX(*x, sizing->BaseX); - if (y != NULL) - *y = dlgUnitsToY(*y, sizing->BaseY); -} - -// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing and https://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx -// this X value is really only for buttons but I don't see a better one :/ -#define winXPadding 4 -#define winYPadding 4 - -void uiWindowsSizingStandardPadding(uiWindowsSizing *sizing, int *x, int *y) -{ - if (x != NULL) - *x = dlgUnitsToX(winXPadding, sizing->BaseX); - if (y != NULL) - *y = dlgUnitsToY(winYPadding, sizing->BaseY); -} diff --git a/deps/libui/windows/slider.cpp b/deps/libui/windows/slider.cpp deleted file mode 100644 index 5c671dda09..0000000000 --- a/deps/libui/windows/slider.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// 20 may 2015 -#include "uipriv_windows.hpp" - -struct uiSlider { - uiWindowsControl c; - HWND hwnd; - void (*onChanged)(uiSlider *, void *); - void *onChangedData; -}; - -static BOOL onWM_HSCROLL(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult) -{ - uiSlider *s = uiSlider(c); - - (*(s->onChanged))(s, s->onChangedData); - *lResult = 0; - return TRUE; -} - -static void uiSliderDestroy(uiControl *c) -{ - uiSlider *s = uiSlider(c); - - uiWindowsUnregisterWM_HSCROLLHandler(s->hwnd); - uiWindowsEnsureDestroyWindow(s->hwnd); - uiFreeControl(uiControl(s)); -} - -uiWindowsControlAllDefaultsExceptDestroy(uiSlider); - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define sliderWidth 107 /* this is actually the shorter progress bar width, but Microsoft doesn't indicate a width */ -#define sliderHeight 15 - -static void uiSliderMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiSlider *s = uiSlider(c); - uiWindowsSizing sizing; - int x, y; - - x = sliderWidth; - y = sliderHeight; - uiWindowsGetSizing(s->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - *width = x; - *height = y; -} - -static void defaultOnChanged(uiSlider *s, void *data) -{ - // do nothing -} - -int uiSliderValue(uiSlider *s) -{ - return SendMessageW(s->hwnd, TBM_GETPOS, 0, 0); -} - -void uiSliderSetValue(uiSlider *s, int value) -{ - // don't use TBM_SETPOSNOTIFY; that triggers an event - SendMessageW(s->hwnd, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) value); -} - -void uiSliderOnChanged(uiSlider *s, void (*f)(uiSlider *, void *), void *data) -{ - s->onChanged = f; - s->onChangedData = data; -} - -uiSlider *uiNewSlider(int min, int max) -{ - uiSlider *s; - int temp; - - if (min >= max) { - temp = min; - min = max; - max = temp; - } - - uiWindowsNewControl(uiSlider, s); - - s->hwnd = uiWindowsEnsureCreateControlHWND(0, - TRACKBAR_CLASSW, L"", - TBS_HORZ | TBS_TOOLTIPS | TBS_TRANSPARENTBKGND | WS_TABSTOP, - hInstance, NULL, - TRUE); - - uiWindowsRegisterWM_HSCROLLHandler(s->hwnd, onWM_HSCROLL, uiControl(s)); - uiSliderOnChanged(s, defaultOnChanged, NULL); - - SendMessageW(s->hwnd, TBM_SETRANGEMIN, (WPARAM) TRUE, (LPARAM) min); - SendMessageW(s->hwnd, TBM_SETRANGEMAX, (WPARAM) TRUE, (LPARAM) max); - SendMessageW(s->hwnd, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) min); - - return s; -} diff --git a/deps/libui/windows/spinbox.cpp b/deps/libui/windows/spinbox.cpp deleted file mode 100644 index 2b6af66d33..0000000000 --- a/deps/libui/windows/spinbox.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// 8 april 2015 -#include "uipriv_windows.hpp" - -struct uiSpinbox { - uiWindowsControl c; - HWND hwnd; - HWND edit; - HWND updown; - void (*onChanged)(uiSpinbox *, void *); - void *onChangedData; - BOOL inhibitChanged; -}; - -// utility functions - -static int value(uiSpinbox *s) -{ - BOOL neededCap = FALSE; - LRESULT val; - - // This verifies the value put in, capping it automatically. - // We don't need to worry about checking for an error; that flag should really be called "did we have to cap?". - // We DO need to set the value in case of a cap though. - val = SendMessageW(s->updown, UDM_GETPOS32, 0, (LPARAM) (&neededCap)); - if (neededCap) { - s->inhibitChanged = TRUE; - SendMessageW(s->updown, UDM_SETPOS32, 0, (LPARAM) val); - s->inhibitChanged = FALSE; - } - return val; -} - -// control implementation - -static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult) -{ - uiSpinbox *s = (uiSpinbox *) c; - WCHAR *wtext; - - if (code != EN_CHANGE) - return FALSE; - if (s->inhibitChanged) - return FALSE; - // We want to allow typing negative numbers; the natural way to do so is to start with a -. - // However, if we just have the code below, the up-down will catch the bare - and reject it. - // Let's fix that. - // This won't handle leading spaces, but spaces aren't allowed *anyway*. - wtext = windowText(s->edit); - if (wcscmp(wtext, L"-") == 0) { - uiFree(wtext); - return TRUE; - } - uiFree(wtext); - // value() does the work for us - value(s); - (*(s->onChanged))(s, s->onChangedData); - return TRUE; -} - -static void uiSpinboxDestroy(uiControl *c) -{ - uiSpinbox *s = uiSpinbox(c); - - uiWindowsUnregisterWM_COMMANDHandler(s->edit); - uiWindowsEnsureDestroyWindow(s->updown); - uiWindowsEnsureDestroyWindow(s->edit); - uiWindowsEnsureDestroyWindow(s->hwnd); - uiFreeControl(uiControl(s)); -} - -// TODO SyncEnableState -uiWindowsControlAllDefaultsExceptDestroy(uiSpinbox) - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -// TODO reduce this? -#define entryWidth 107 /* this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary */ -#define entryHeight 14 - -static void uiSpinboxMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiSpinbox *s = uiSpinbox(c); - uiWindowsSizing sizing; - int x, y; - - x = entryWidth; - y = entryHeight; - // note that we go by the edit here - uiWindowsGetSizing(s->edit, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); - *width = x; - *height = y; -} - -static void spinboxArrangeChildren(uiSpinbox *s) -{ - LONG_PTR controlID; - HWND insertAfter; - - controlID = 100; - insertAfter = NULL; - uiWindowsEnsureAssignControlIDZOrder(s->edit, &controlID, &insertAfter); - uiWindowsEnsureAssignControlIDZOrder(s->updown, &controlID, &insertAfter); -} - -// an up-down control will only properly position itself the first time -// stupidly, there are no messages to force a size calculation, nor can I seem to reset the buddy window to force a new position -// alas, we have to make a new up/down control each time :( -static void recreateUpDown(uiSpinbox *s) -{ - BOOL preserve = FALSE; - int current; - // Microsoft's commctrl.h says to use this type - INT min, max; - - if (s->updown != NULL) { - preserve = TRUE; - current = value(s); - SendMessageW(s->updown, UDM_GETRANGE32, (WPARAM) (&min), (LPARAM) (&max)); - uiWindowsEnsureDestroyWindow(s->updown); - } - s->inhibitChanged = TRUE; - s->updown = CreateWindowExW(0, - UPDOWN_CLASSW, L"", - // no WS_VISIBLE; we set visibility ourselves - // up-down control should not be a tab stop - WS_CHILD | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_HOTTRACK | UDS_NOTHOUSANDS | UDS_SETBUDDYINT, - // this is important; it's necessary for autosizing to work - 0, 0, 0, 0, - s->hwnd, NULL, hInstance, NULL); - if (s->updown == NULL) - logLastError(L"error creating updown"); - SendMessageW(s->updown, UDM_SETBUDDY, (WPARAM) (s->edit), 0); - if (preserve) { - SendMessageW(s->updown, UDM_SETRANGE32, (WPARAM) min, (LPARAM) max); - SendMessageW(s->updown, UDM_SETPOS32, 0, (LPARAM) current); - } - // preserve the Z-order - spinboxArrangeChildren(s); - // TODO properly show/enable - ShowWindow(s->updown, SW_SHOW); - s->inhibitChanged = FALSE; -} - -static void spinboxRelayout(uiSpinbox *s) -{ - RECT r; - - // make the edit fill the container first; the new updown will resize it - uiWindowsEnsureGetClientRect(s->hwnd, &r); - uiWindowsEnsureMoveWindowDuringResize(s->edit, r.left, r.top, r.right - r.left, r.bottom - r.top); - recreateUpDown(s); -} - -static void defaultOnChanged(uiSpinbox *s, void *data) -{ - // do nothing -} - -int uiSpinboxValue(uiSpinbox *s) -{ - return value(s); -} - -void uiSpinboxSetValue(uiSpinbox *s, int value) -{ - s->inhibitChanged = TRUE; - SendMessageW(s->updown, UDM_SETPOS32, 0, (LPARAM) value); - s->inhibitChanged = FALSE; -} - -void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *, void *), void *data) -{ - s->onChanged = f; - s->onChangedData = data; -} - -static void onResize(uiWindowsControl *c) -{ - spinboxRelayout(uiSpinbox(c)); -} - -uiSpinbox *uiNewSpinbox(int min, int max) -{ - uiSpinbox *s; - int temp; - - if (min >= max) { - temp = min; - min = max; - max = temp; - } - - uiWindowsNewControl(uiSpinbox, s); - - s->hwnd = uiWindowsMakeContainer(uiWindowsControl(s), onResize); - - s->edit = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE, - L"edit", L"", - // don't use ES_NUMBER; it doesn't allow typing in a leading - - ES_AUTOHSCROLL | ES_LEFT | ES_NOHIDESEL | WS_TABSTOP, - hInstance, NULL, - TRUE); - uiWindowsEnsureSetParentHWND(s->edit, s->hwnd); - - uiWindowsRegisterWM_COMMANDHandler(s->edit, onWM_COMMAND, uiControl(s)); - uiSpinboxOnChanged(s, defaultOnChanged, NULL); - - recreateUpDown(s); - s->inhibitChanged = TRUE; - SendMessageW(s->updown, UDM_SETRANGE32, (WPARAM) min, (LPARAM) max); - SendMessageW(s->updown, UDM_SETPOS32, 0, (LPARAM) min); - s->inhibitChanged = FALSE; - - return s; -} diff --git a/deps/libui/windows/stddialogs.cpp b/deps/libui/windows/stddialogs.cpp deleted file mode 100644 index 89d26bacd7..0000000000 --- a/deps/libui/windows/stddialogs.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// 22 may 2015 -#include "uipriv_windows.hpp" - -// TODO document all this is what we want -// TODO do the same for font and color buttons - -// notes: -// - FOS_SUPPORTSTREAMABLEITEMS doesn't seem to be supported on windows vista, or at least not with the flags we use -// - even with FOS_NOVALIDATE the dialogs will reject invalid filenames (at least on Vista, anyway) -// - lack of FOS_NOREADONLYRETURN doesn't seem to matter on Windows 7 - -// TODO -// - http://blogs.msdn.com/b/wpfsdk/archive/2006/10/26/uncommon-dialogs--font-chooser-and-color-picker-dialogs.aspx -// - when a dialog is active, tab navigation in other windows stops working -// - when adding uiOpenFolder(), use IFileDialog as well - https://msdn.microsoft.com/en-us/library/windows/desktop/bb762115%28v=vs.85%29.aspx - -#define windowHWND(w) ((HWND) uiControlHandle(uiControl(w))) - -char *commonItemDialog(HWND parent, REFCLSID clsid, REFIID iid, FILEOPENDIALOGOPTIONS optsadd) -{ - IFileDialog *d = NULL; - FILEOPENDIALOGOPTIONS opts; - IShellItem *result = NULL; - WCHAR *wname = NULL; - char *name = NULL; - HRESULT hr; - - hr = CoCreateInstance(clsid, - NULL, CLSCTX_INPROC_SERVER, - iid, (LPVOID *) (&d)); - if (hr != S_OK) { - logHRESULT(L"error creating common item dialog", hr); - // always return NULL on error - goto out; - } - hr = d->GetOptions(&opts); - if (hr != S_OK) { - logHRESULT(L"error getting current options", hr); - goto out; - } - opts |= optsadd; - // the other platforms don't check read-only; we won't either - opts &= ~FOS_NOREADONLYRETURN; - hr = d->SetOptions(opts); - if (hr != S_OK) { - logHRESULT(L"error setting options", hr); - goto out; - } - hr = d->Show(parent); - if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) - // cancelled; return NULL like we have ready - goto out; - if (hr != S_OK) { - logHRESULT(L"error showing dialog", hr); - goto out; - } - hr = d->GetResult(&result); - if (hr != S_OK) { - logHRESULT(L"error getting dialog result", hr); - goto out; - } - hr = result->GetDisplayName(SIGDN_FILESYSPATH, &wname); - if (hr != S_OK) { - logHRESULT(L"error getting filename", hr); - goto out; - } - name = toUTF8(wname); - -out: - if (wname != NULL) - CoTaskMemFree(wname); - if (result != NULL) - result->Release(); - if (d != NULL) - d->Release(); - return name; -} - -char *uiOpenFile(uiWindow *parent) -{ - char *res; - - disableAllWindowsExcept(parent); - res = commonItemDialog(windowHWND(parent), - CLSID_FileOpenDialog, IID_IFileOpenDialog, - FOS_NOCHANGEDIR | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_SHAREAWARE | FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS | FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE); - enableAllWindowsExcept(parent); - return res; -} - -char *uiSaveFile(uiWindow *parent) -{ - char *res; - - disableAllWindowsExcept(parent); - res = commonItemDialog(windowHWND(parent), - CLSID_FileSaveDialog, IID_IFileSaveDialog, - FOS_OVERWRITEPROMPT | FOS_NOCHANGEDIR | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_SHAREAWARE | FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS | FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE); - enableAllWindowsExcept(parent); - return res; -} - -// TODO switch to TaskDialogIndirect()? - -static void msgbox(HWND parent, const char *title, const char *description, TASKDIALOG_COMMON_BUTTON_FLAGS buttons, PCWSTR icon) -{ - WCHAR *wtitle, *wdescription; - HRESULT hr; - - wtitle = toUTF16(title); - wdescription = toUTF16(description); - - hr = TaskDialog(parent, NULL, NULL, wtitle, wdescription, buttons, icon, NULL); - if (hr != S_OK) - logHRESULT(L"error showing task dialog", hr); - - uiFree(wdescription); - uiFree(wtitle); -} - -void uiMsgBox(uiWindow *parent, const char *title, const char *description) -{ - disableAllWindowsExcept(parent); - msgbox(windowHWND(parent), title, description, TDCBF_OK_BUTTON, NULL); - enableAllWindowsExcept(parent); -} - -void uiMsgBoxError(uiWindow *parent, const char *title, const char *description) -{ - disableAllWindowsExcept(parent); - msgbox(windowHWND(parent), title, description, TDCBF_OK_BUTTON, TD_ERROR_ICON); - enableAllWindowsExcept(parent); -} diff --git a/deps/libui/windows/tab.cpp b/deps/libui/windows/tab.cpp deleted file mode 100644 index 365f5a1fa9..0000000000 --- a/deps/libui/windows/tab.cpp +++ /dev/null @@ -1,287 +0,0 @@ -// 16 may 2015 -#include "uipriv_windows.hpp" - -// You don't add controls directly to a tab control on Windows; instead you make them siblings and swap between them on a TCN_SELCHANGING/TCN_SELCHANGE notification pair. -// In addition, you use dialogs because they can be textured properly; other controls cannot. (Things will look wrong if the tab background in the current theme is fancy if you just use the tab background by itself; see http://stackoverflow.com/questions/30087540/why-are-my-programss-tab-controls-rendering-their-background-in-a-blocky-way-b.) - -struct uiTab { - uiWindowsControl c; - HWND hwnd; // of the outer container - HWND tabHWND; // of the tab control itself - std::vector *pages; - HWND parent; -}; - -// utility functions - -static LRESULT curpage(uiTab *t) -{ - return SendMessageW(t->tabHWND, TCM_GETCURSEL, 0, 0); -} - -static struct tabPage *tabPage(uiTab *t, int i) -{ - return (*(t->pages))[i]; -} - -static void tabPageRect(uiTab *t, RECT *r) -{ - // this rect needs to be in parent window coordinates, but TCM_ADJUSTRECT wants a window rect, which is screen coordinates - // because we have each page as a sibling of the tab, use the tab's own rect as the input rect - uiWindowsEnsureGetWindowRect(t->tabHWND, r); - SendMessageW(t->tabHWND, TCM_ADJUSTRECT, (WPARAM) FALSE, (LPARAM) r); - // and get it in terms of the container instead of the screen - mapWindowRect(NULL, t->hwnd, r); -} - -static void tabRelayout(uiTab *t) -{ - struct tabPage *page; - RECT r; - - // first move the tab control itself - uiWindowsEnsureGetClientRect(t->hwnd, &r); - uiWindowsEnsureMoveWindowDuringResize(t->tabHWND, r.left, r.top, r.right - r.left, r.bottom - r.top); - - // then the current page - if (t->pages->size() == 0) - return; - page = tabPage(t, curpage(t)); - tabPageRect(t, &r); - uiWindowsEnsureMoveWindowDuringResize(page->hwnd, r.left, r.top, r.right - r.left, r.bottom - r.top); -} - -static void showHidePage(uiTab *t, LRESULT which, int hide) -{ - struct tabPage *page; - - if (which == (LRESULT) (-1)) - return; - page = tabPage(t, which); - if (hide) - ShowWindow(page->hwnd, SW_HIDE); - else { - ShowWindow(page->hwnd, SW_SHOW); - // we only resize the current page, so we have to resize it; before we can do that, we need to make sure we are of the right size - uiWindowsControlMinimumSizeChanged(uiWindowsControl(t)); - } -} - -// control implementation - -static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult) -{ - uiTab *t = uiTab(c); - - if (nm->code != TCN_SELCHANGING && nm->code != TCN_SELCHANGE) - return FALSE; - showHidePage(t, curpage(t), nm->code == TCN_SELCHANGING); - *lResult = 0; - if (nm->code == TCN_SELCHANGING) - *lResult = FALSE; - return TRUE; -} - -static void uiTabDestroy(uiControl *c) -{ - uiTab *t = uiTab(c); - uiControl *child; - - for (struct tabPage *&page : *(t->pages)) { - child = page->child; - tabPageDestroy(page); - if (child != NULL) { - uiControlSetParent(child, NULL); - uiControlDestroy(child); - } - } - delete t->pages; - uiWindowsUnregisterWM_NOTIFYHandler(t->tabHWND); - uiWindowsEnsureDestroyWindow(t->tabHWND); - uiWindowsEnsureDestroyWindow(t->hwnd); - uiFreeControl(uiControl(t)); -} - -uiWindowsControlDefaultHandle(uiTab) -uiWindowsControlDefaultParent(uiTab) -uiWindowsControlDefaultSetParent(uiTab) -uiWindowsControlDefaultToplevel(uiTab) -uiWindowsControlDefaultVisible(uiTab) -uiWindowsControlDefaultShow(uiTab) -uiWindowsControlDefaultHide(uiTab) -uiWindowsControlDefaultEnabled(uiTab) -uiWindowsControlDefaultEnable(uiTab) -uiWindowsControlDefaultDisable(uiTab) - -static void uiTabSyncEnableState(uiWindowsControl *c, int enabled) -{ - uiTab *t = uiTab(c); - - if (uiWindowsShouldStopSyncEnableState(uiWindowsControl(t), enabled)) - return; - EnableWindow(t->tabHWND, enabled); - for (struct tabPage *&page : *(t->pages)) - if (page->child != NULL) - uiWindowsControlSyncEnableState(uiWindowsControl(page->child), enabled); -} - -uiWindowsControlDefaultSetParentHWND(uiTab) - -static void uiTabMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiTab *t = uiTab(c); - int pagewid, pageht; - struct tabPage *page; - RECT r; - - // only consider the current page - pagewid = 0; - pageht = 0; - if (t->pages->size() != 0) { - page = tabPage(t, curpage(t)); - tabPageMinimumSize(page, &pagewid, &pageht); - } - - r.left = 0; - r.top = 0; - r.right = pagewid; - r.bottom = pageht; - // this also includes the tabs themselves - SendMessageW(t->tabHWND, TCM_ADJUSTRECT, (WPARAM) TRUE, (LPARAM) (&r)); - *width = r.right - r.left; - *height = r.bottom - r.top; -} - -static void uiTabMinimumSizeChanged(uiWindowsControl *c) -{ - uiTab *t = uiTab(c); - - if (uiWindowsControlTooSmall(uiWindowsControl(t))) { - uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(t)); - return; - } - tabRelayout(t); -} - -uiWindowsControlDefaultLayoutRect(uiTab) -uiWindowsControlDefaultAssignControlIDZOrder(uiTab) - -static void uiTabChildVisibilityChanged(uiWindowsControl *c) -{ - // TODO eliminate the redundancy - uiWindowsControlMinimumSizeChanged(c); -} - -static void tabArrangePages(uiTab *t) -{ - LONG_PTR controlID = 100; - HWND insertAfter = NULL; - - // TODO is this first or last? - uiWindowsEnsureAssignControlIDZOrder(t->tabHWND, &controlID, &insertAfter); - for (struct tabPage *&page : *(t->pages)) - uiWindowsEnsureAssignControlIDZOrder(page->hwnd, &controlID, &insertAfter); -} - -void uiTabAppend(uiTab *t, const char *name, uiControl *child) -{ - uiTabInsertAt(t, name, t->pages->size(), child); -} - -void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) -{ - struct tabPage *page; - LRESULT hide, show; - TCITEMW item; - WCHAR *wname; - - // see below - hide = curpage(t); - - if (child != NULL) - uiControlSetParent(child, uiControl(t)); - - page = newTabPage(child); - uiWindowsEnsureSetParentHWND(page->hwnd, t->hwnd); - t->pages->insert(t->pages->begin() + n, page); - tabArrangePages(t); - - ZeroMemory(&item, sizeof (TCITEMW)); - item.mask = TCIF_TEXT; - wname = toUTF16(name); - item.pszText = wname; - if (SendMessageW(t->tabHWND, TCM_INSERTITEM, (WPARAM) n, (LPARAM) (&item)) == (LRESULT) -1) - logLastError(L"error adding tab to uiTab"); - uiFree(wname); - - // we need to do this because adding the first tab doesn't send a TCN_SELCHANGE; it just shows the page - show = curpage(t); - if (show != hide) { - showHidePage(t, hide, 1); - showHidePage(t, show, 0); - } -} - -void uiTabDelete(uiTab *t, int n) -{ - struct tabPage *page; - - // first delete the tab from the tab control - // if this is the current tab, no tab will be selected, which is good - if (SendMessageW(t->tabHWND, TCM_DELETEITEM, (WPARAM) n, 0) == FALSE) - logLastError(L"error deleting uiTab tab"); - - // now delete the page itself - page = tabPage(t, n); - if (page->child != NULL) - uiControlSetParent(page->child, NULL); - tabPageDestroy(page); - t->pages->erase(t->pages->begin() + n); -} - -int uiTabNumPages(uiTab *t) -{ - return t->pages->size(); -} - -int uiTabMargined(uiTab *t, int n) -{ - return tabPage(t, n)->margined; -} - -void uiTabSetMargined(uiTab *t, int n, int margined) -{ - struct tabPage *page; - - page = tabPage(t, n); - page->margined = margined; - // even if the page doesn't have a child it might still have a new minimum size with margins; this is the easiest way to verify it - uiWindowsControlMinimumSizeChanged(uiWindowsControl(t)); -} - -static void onResize(uiWindowsControl *c) -{ - tabRelayout(uiTab(c)); -} - -uiTab *uiNewTab(void) -{ - uiTab *t; - - uiWindowsNewControl(uiTab, t); - - t->hwnd = uiWindowsMakeContainer(uiWindowsControl(t), onResize); - - t->tabHWND = uiWindowsEnsureCreateControlHWND(0, - WC_TABCONTROLW, L"", - TCS_TOOLTIPS | WS_TABSTOP, - hInstance, NULL, - TRUE); - uiWindowsEnsureSetParentHWND(t->tabHWND, t->hwnd); - - uiWindowsRegisterWM_NOTIFYHandler(t->tabHWND, onWM_NOTIFY, uiControl(t)); - - t->pages = new std::vector; - - return t; -} diff --git a/deps/libui/windows/tabpage.cpp b/deps/libui/windows/tabpage.cpp deleted file mode 100644 index 5283ce7909..0000000000 --- a/deps/libui/windows/tabpage.cpp +++ /dev/null @@ -1,131 +0,0 @@ -// 30 may 2015 -#include "uipriv_windows.hpp" - -// TODO refine error handling - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx -#define tabMargin 7 - -static void tabPageMargins(struct tabPage *tp, int *mx, int *my) -{ - uiWindowsSizing sizing; - - *mx = 0; - *my = 0; - if (!tp->margined) - return; - uiWindowsGetSizing(tp->hwnd, &sizing); - *mx = tabMargin; - *my = tabMargin; - uiWindowsSizingDlgUnitsToPixels(&sizing, mx, my); -} - -static void tabPageRelayout(struct tabPage *tp) -{ - RECT r; - int mx, my; - HWND child; - - if (tp->child == NULL) - return; - uiWindowsEnsureGetClientRect(tp->hwnd, &r); - tabPageMargins(tp, &mx, &my); - r.left += mx; - r.top += my; - r.right -= mx; - r.bottom -= my; - child = (HWND) uiControlHandle(tp->child); - uiWindowsEnsureMoveWindowDuringResize(child, r.left, r.top, r.right - r.left, r.bottom - r.top); -} - -// dummy dialog procedure; see below for details -// let's handle parent messages here to avoid needing to subclass -// TODO do we need to handle DM_GETDEFID/DM_SETDEFID here too because of the ES_WANTRETURN stuff at http://blogs.msdn.com/b/oldnewthing/archive/2007/08/20/4470527.aspx? what about multiple default buttons (TODO)? -// TODO we definitely need to do something about edit message handling; it does a fake close of our parent on pressing escape, causing uiWindow to stop responding to maximizes but still respond to events and then die horribly on destruction -static INT_PTR CALLBACK dlgproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - struct tabPage *tp; - LRESULT lResult; - - if (uMsg == WM_INITDIALOG) { - tp = (struct tabPage *) lParam; - tp->hwnd = hwnd; - SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR) tp); - return TRUE; - } - if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE) { - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (LONG_PTR) lResult); - return TRUE; - } - if (uMsg == WM_WINDOWPOSCHANGED) { - tp = (struct tabPage *) GetWindowLongPtrW(hwnd, DWLP_USER); - tabPageRelayout(tp); - // pretend the dialog hasn't handled this just in case it needs to do something special - return FALSE; - } - - // unthemed dialogs don't respond to WM_PRINTCLIENT - // fortunately they don't have any special painting - if (uMsg == WM_PRINTCLIENT) { - // don't worry about the return value; hopefully DefWindowProcW() caught it (if not the dialog procedure itself) - // we COULD paint the dialog background brush ourselves but meh, it works - SendMessageW(hwnd, WM_ERASEBKGND, wParam, lParam); - // and pretend we did nothing just so the themed dialog can still paint its content - // TODO see if w ecan avoid erasing the background in this case in the first place, or if we even need to - return FALSE; - } - - return FALSE; -} - -struct tabPage *newTabPage(uiControl *child) -{ - struct tabPage *tp; - HRESULT hr; - - tp = uiNew(struct tabPage); - - // unfortunately this needs to be a proper dialog for EnableThemeDialogTexture() to work; CreateWindowExW() won't suffice - if (CreateDialogParamW(hInstance, MAKEINTRESOURCE(rcTabPageDialog), - utilWindow, dlgproc, (LPARAM) tp) == NULL) - logLastError(L"error creating tab page"); - - tp->child = child; - if (tp->child != NULL) { - uiWindowsEnsureSetParentHWND((HWND) uiControlHandle(tp->child), tp->hwnd); - uiWindowsControlAssignSoleControlIDZOrder(uiWindowsControl(tp->child)); - } - - hr = EnableThemeDialogTexture(tp->hwnd, ETDT_ENABLE | ETDT_USETABTEXTURE | ETDT_ENABLETAB); - if (hr != S_OK) - logHRESULT(L"error setting tab page background", hr); - // continue anyway; it'll look wrong but eh - - // and start the tab page hidden - ShowWindow(tp->hwnd, SW_HIDE); - - return tp; -} - -void tabPageDestroy(struct tabPage *tp) -{ - // don't destroy the child with the page - if (tp->child != NULL) - uiWindowsControlSetParentHWND(uiWindowsControl(tp->child), NULL); - // don't call EndDialog(); that's for the DialogBox() family of functions instead of CreateDialog() - uiWindowsEnsureDestroyWindow(tp->hwnd); - uiFree(tp); -} - -void tabPageMinimumSize(struct tabPage *tp, int *width, int *height) -{ - int mx, my; - - *width = 0; - *height = 0; - if (tp->child != NULL) - uiWindowsControlMinimumSize(uiWindowsControl(tp->child), width, height); - tabPageMargins(tp, &mx, &my); - *width += 2 * mx; - *height += 2 * my; -} diff --git a/deps/libui/windows/text.cpp b/deps/libui/windows/text.cpp deleted file mode 100644 index af79fb8078..0000000000 --- a/deps/libui/windows/text.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// 9 april 2015 -#include "uipriv_windows.hpp" - -WCHAR *windowTextAndLen(HWND hwnd, LRESULT *len) -{ - LRESULT n; - WCHAR *text; - - n = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); - if (len != NULL) - *len = n; - // WM_GETTEXTLENGTH does not include the null terminator - text = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]"); - // note the comparison: the size includes the null terminator, but the return does not - if (GetWindowTextW(hwnd, text, n + 1) != n) { - logLastError(L"error getting window text"); - // on error, return an empty string to be safe - *text = L'\0'; - if (len != NULL) - *len = 0; - } - return text; -} - -WCHAR *windowText(HWND hwnd) -{ - return windowTextAndLen(hwnd, NULL); -} - -void setWindowText(HWND hwnd, WCHAR *wtext) -{ - if (SetWindowTextW(hwnd, wtext) == 0) - logLastError(L"error setting window text"); -} - -void uiFreeText(char *text) -{ - uiFree(text); -} - -int uiWindowsWindowTextWidth(HWND hwnd) -{ - LRESULT len; - WCHAR *text; - HDC dc; - HFONT prevfont; - SIZE size; - - size.cx = 0; - size.cy = 0; - - text = windowTextAndLen(hwnd, &len); - if (len == 0) // no text; nothing to do - goto noTextOrError; - - // now we can do the calculations - dc = GetDC(hwnd); - if (dc == NULL) { - logLastError(L"error getting DC"); - // on any error, assume no text - goto noTextOrError; - } - prevfont = (HFONT) SelectObject(dc, hMessageFont); - if (prevfont == NULL) { - logLastError(L"error loading control font into device context"); - ReleaseDC(hwnd, dc); - goto noTextOrError; - } - if (GetTextExtentPoint32W(dc, text, len, &size) == 0) { - logLastError(L"error getting text extent point"); - // continue anyway, assuming size is 0 - size.cx = 0; - size.cy = 0; - } - // continue on errors; we got what we want - if (SelectObject(dc, prevfont) != hMessageFont) - logLastError(L"error restoring previous font into device context"); - if (ReleaseDC(hwnd, dc) == 0) - logLastError(L"error releasing DC"); - - uiFree(text); - return size.cx; - -noTextOrError: - uiFree(text); - return 0; -} - -char *uiWindowsWindowText(HWND hwnd) -{ - WCHAR *wtext; - char *text; - - wtext = windowText(hwnd); - text = toUTF8(wtext); - uiFree(wtext); - return text; -} - -void uiWindowsSetWindowText(HWND hwnd, const char *text) -{ - WCHAR *wtext; - - wtext = toUTF16(text); - setWindowText(hwnd, wtext); - uiFree(wtext); -} diff --git a/deps/libui/windows/uipriv_windows.hpp b/deps/libui/windows/uipriv_windows.hpp deleted file mode 100644 index 6ffe09f1ad..0000000000 --- a/deps/libui/windows/uipriv_windows.hpp +++ /dev/null @@ -1,164 +0,0 @@ -// 21 april 2016 -#include "winapi.hpp" -#include "../ui.h" -#include "../ui_windows.h" -#include "../common/uipriv.h" -#include "resources.hpp" -#include "compilerver.hpp" - -// ui internal window messages -enum { - // redirected WM_COMMAND and WM_NOTIFY - msgCOMMAND = WM_APP + 0x40, // start offset just to be safe - msgNOTIFY, - msgHSCROLL, - msgQueued, - msgD2DScratchPaint, - msgD2DScratchLButtonDown, -}; - -// alloc.cpp -extern void initAlloc(void); -extern void uninitAlloc(void); - -// events.cpp -extern BOOL runWM_COMMAND(WPARAM wParam, LPARAM lParam, LRESULT *lResult); -extern BOOL runWM_NOTIFY(WPARAM wParam, LPARAM lParam, LRESULT *lResult); -extern BOOL runWM_HSCROLL(WPARAM wParam, LPARAM lParam, LRESULT *lResult); -extern void issueWM_WININICHANGE(WPARAM wParam, LPARAM lParam); - -// utf16.cpp -#define emptyUTF16() ((WCHAR *) uiAlloc(1 * sizeof (WCHAR), "WCHAR[]")) -#define emptyUTF8() ((char *) uiAlloc(1 * sizeof (char), "char[]")) -extern WCHAR *toUTF16(const char *str); -extern char *toUTF8(const WCHAR *wstr); -extern WCHAR *utf16dup(const WCHAR *orig); -extern WCHAR *strf(const WCHAR *format, ...); -extern WCHAR *vstrf(const WCHAR *format, va_list ap); -extern char *LFtoCRLF(const char *lfonly); -extern void CRLFtoLF(char *s); -extern WCHAR *ftoutf16(double d); -extern WCHAR *itoutf16(int i); - -// debug.cpp -// see http://stackoverflow.com/questions/14421656/is-there-widely-available-wide-character-variant-of-file -// we turn __LINE__ into a string because PRIiMAX can't be converted to a wide string in MSVC (it seems to be defined as "ll" "i" according to the compiler errors) -// also note the use of __FUNCTION__ here; __func__ doesn't seem to work for some reason -#define _ws2(m) L ## m -#define _ws(m) _ws2(m) -#define _ws2n(m) L ## #m -#define _wsn(m) _ws2n(m) -#define debugargs const WCHAR *file, const WCHAR *line, const WCHAR *func -extern HRESULT _logLastError(debugargs, const WCHAR *s); -#ifdef _MSC_VER -#define logLastError(s) _logLastError(_ws(__FILE__), _wsn(__LINE__), _ws(__FUNCTION__), s) -#else -#define logLastError(s) _logLastError(_ws(__FILE__), _wsn(__LINE__), L"TODO none of the function name macros are macros in MinGW", s) -#endif -extern HRESULT _logHRESULT(debugargs, const WCHAR *s, HRESULT hr); -#ifdef _MSC_VER -#define logHRESULT(s, hr) _logHRESULT(_ws(__FILE__), _wsn(__LINE__), _ws(__FUNCTION__), s, hr) -#else -#define logHRESULT(s, hr) _logHRESULT(_ws(__FILE__), _wsn(__LINE__), L"TODO none of the function name macros are macros in MinGW", s, hr) -#endif - -// winutil.cpp -extern int windowClassOf(HWND hwnd, ...); -extern void mapWindowRect(HWND from, HWND to, RECT *r); -extern DWORD getStyle(HWND hwnd); -extern void setStyle(HWND hwnd, DWORD style); -extern DWORD getExStyle(HWND hwnd); -extern void setExStyle(HWND hwnd, DWORD exstyle); -extern void clientSizeToWindowSize(HWND hwnd, int *width, int *height, BOOL hasMenubar); -extern HWND parentOf(HWND child); -extern HWND parentToplevel(HWND child); -extern void setWindowInsertAfter(HWND hwnd, HWND insertAfter); -extern HWND getDlgItem(HWND hwnd, int id); -extern void invalidateRect(HWND hwnd, RECT *r, BOOL erase); - -// text.cpp -extern WCHAR *windowTextAndLen(HWND hwnd, LRESULT *len); -extern WCHAR *windowText(HWND hwnd); -extern void setWindowText(HWND hwnd, WCHAR *wtext); - -// init.cpp -extern HINSTANCE hInstance; -extern int nCmdShow; -extern HFONT hMessageFont; -extern HBRUSH hollowBrush; -extern uiInitOptions options; - -// utilwin.cpp -extern HWND utilWindow; -extern const char *initUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor); -extern void uninitUtilWindow(void); - -// main.cpp -extern int registerMessageFilter(void); -extern void unregisterMessageFilter(void); - -// parent.cpp -extern void paintContainerBackground(HWND hwnd, HDC dc, RECT *paintRect); -extern BOOL handleParentMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult); - -// d2dscratch.cpp -extern ATOM registerD2DScratchClass(HICON hDefaultIcon, HCURSOR hDefaultCursor); -extern void unregisterD2DScratchClass(void); -extern HWND newD2DScratch(HWND parent, RECT *rect, HMENU controlID, SUBCLASSPROC subclass, DWORD_PTR subclassData); - -// area.cpp -#define areaClass L"libui_uiAreaClass" -extern ATOM registerAreaClass(HICON, HCURSOR); -extern void unregisterArea(void); - -// areaevents.cpp -extern BOOL areaFilter(MSG *); - -// window.cpp -extern ATOM registerWindowClass(HICON, HCURSOR); -extern void unregisterWindowClass(void); -extern void ensureMinimumWindowSize(uiWindow *); -extern void disableAllWindowsExcept(uiWindow *which); -extern void enableAllWindowsExcept(uiWindow *which); - -// container.cpp -#define containerClass L"libui_uiContainerClass" -extern ATOM initContainer(HICON, HCURSOR); -extern void uninitContainer(void); - -// tabpage.cpp -struct tabPage { - HWND hwnd; - uiControl *child; - BOOL margined; -}; -extern struct tabPage *newTabPage(uiControl *child); -extern void tabPageDestroy(struct tabPage *tp); -extern void tabPageMinimumSize(struct tabPage *tp, int *width, int *height); - -// colordialog.cpp -struct colorDialogRGBA { - double r; - double g; - double b; - double a; -}; -extern BOOL showColorDialog(HWND parent, struct colorDialogRGBA *c); - -// sizing.cpp -extern void getSizing(HWND hwnd, uiWindowsSizing *sizing, HFONT font); - -// graphemes.cpp -extern size_t *graphemes(WCHAR *msg); - -// TODO move into a dedicated file abibugs.cpp when we rewrite the drawing code -extern D2D1_SIZE_F realGetSize(ID2D1RenderTarget *rt); - - - - -// TODO -#include "_uipriv_migrate.hpp" - -// draw.cpp -extern ID2D1DCRenderTarget *makeHDCRenderTarget(HDC dc, RECT *r); diff --git a/deps/libui/windows/utf16.cpp b/deps/libui/windows/utf16.cpp deleted file mode 100644 index 98954d0ada..0000000000 --- a/deps/libui/windows/utf16.cpp +++ /dev/null @@ -1,153 +0,0 @@ -// 21 april 2016 -#include "uipriv_windows.hpp" - -// see http://stackoverflow.com/a/29556509/3408572 - -#define MBTWC(str, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, bufsiz) - -WCHAR *toUTF16(const char *str) -{ - WCHAR *wstr; - int n; - - if (*str == '\0') // empty string - return emptyUTF16(); - n = MBTWC(str, NULL, 0); - if (n == 0) { - logLastError(L"error figuring out number of characters to convert to"); - return emptyUTF16(); - } - wstr = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]"); - if (MBTWC(str, wstr, n) != n) { - logLastError(L"error converting from UTF-8 to UTF-16"); - // and return an empty string - *wstr = L'\0'; - } - return wstr; -} - -#define WCTMB(wstr, str, bufsiz) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, bufsiz, NULL, NULL) - -char *toUTF8(const WCHAR *wstr) -{ - char *str; - int n; - - if (*wstr == L'\0') // empty string - return emptyUTF8(); - n = WCTMB(wstr, NULL, 0); - if (n == 0) { - logLastError(L"error figuring out number of characters to convert to"); - return emptyUTF8(); - } - str = (char *) uiAlloc(n * sizeof (char), "char[]"); - if (WCTMB(wstr, str, n) != n) { - logLastError(L"error converting from UTF-16 to UTF-8"); - // and return an empty string - *str = '\0'; - } - return str; -} - -WCHAR *utf16dup(const WCHAR *orig) -{ - WCHAR *out; - size_t len; - - len = wcslen(orig); - out = (WCHAR *) uiAlloc((len + 1) * sizeof (WCHAR), "WCHAR[]"); - wcscpy_s(out, len + 1, orig); - return out; -} - -WCHAR *strf(const WCHAR *format, ...) -{ - va_list ap; - WCHAR *str; - - va_start(ap, format); - str = vstrf(format, ap); - va_end(ap); - return str; -} - -WCHAR *vstrf(const WCHAR *format, va_list ap) -{ - va_list ap2; - WCHAR *buf; - size_t n; - - if (*format == L'\0') - return emptyUTF16(); - - va_copy(ap2, ap); - n = _vscwprintf(format, ap2); - va_end(ap2); - n++; // terminating L'\0' - - buf = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]"); - // includes terminating L'\0' according to example in https://msdn.microsoft.com/en-us/library/xa1a1a6z.aspx - vswprintf_s(buf, n, format, ap); - - return buf; -} - -// Let's shove these utility routines here too. -// Prerequisite: lfonly is UTF-8. -char *LFtoCRLF(const char *lfonly) -{ - char *crlf; - size_t i, len; - char *out; - - len = strlen(lfonly); - crlf = (char *) uiAlloc((len * 2 + 1) * sizeof (char), "char[]"); - out = crlf; - for (i = 0; i < len; i++) { - if (*lfonly == '\n') - *crlf++ = '\r'; - *crlf++ = *lfonly++; - } - *crlf = '\0'; - return out; -} - -// Prerequisite: s is UTF-8. -void CRLFtoLF(char *s) -{ - char *t = s; - - for (; *s != '\0'; s++) { - // be sure to preserve \rs that are genuinely there - if (*s == '\r' && *(s + 1) == '\n') - continue; - *t++ = *s; - } - *t = '\0'; - // pad out the rest of t, just to be safe - while (t != s) - *t++ = '\0'; -} - -// std::to_string() always uses %f; we want %g -// fortunately std::iostream seems to use %g by default so -WCHAR *ftoutf16(double d) -{ - std::wostringstream ss; - std::wstring s; - - ss << d; - s = ss.str(); // to be safe - return utf16dup(s.c_str()); -} - -// to complement the above -WCHAR *itoutf16(int i) -{ - std::wostringstream ss; - std::wstring s; - - ss << i; - s = ss.str(); // to be safe - return utf16dup(s.c_str()); -} diff --git a/deps/libui/windows/utilwin.cpp b/deps/libui/windows/utilwin.cpp deleted file mode 100644 index 414ae83aba..0000000000 --- a/deps/libui/windows/utilwin.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// 14 may 2015 -#include "uipriv_windows.hpp" - -// The utility window is a special window that performs certain tasks internal to libui. -// It is not a message-only window, and it is always hidden and disabled. -// Its roles: -// - It is the initial parent of all controls. When a control loses its parent, it also becomes that control's parent. -// - It handles WM_QUERYENDSESSION and console end session requests. -// - It handles WM_WININICHANGE and forwards the message to any child windows that request it. -// - It handles executing functions queued to run by uiQueueMain(). - -#define utilWindowClass L"libui_utilWindowClass" - -HWND utilWindow; - -static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - void (*qf)(void *); - LRESULT lResult; - - if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE) - return lResult; - switch (uMsg) { - case WM_QUERYENDSESSION: - // TODO block handler - if (shouldQuit()) { - uiQuit(); - return TRUE; - } - return FALSE; - case WM_WININICHANGE: - issueWM_WININICHANGE(wParam, lParam); - return 0; - case msgQueued: - qf = (void (*)(void *)) wParam; - (*qf)((void *) lParam); - return 0; - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - -const char *initUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = utilWindowClass; - wc.lpfnWndProc = utilWindowWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - if (RegisterClass(&wc) == 0) - // see init.cpp for an explanation of the =s - return "=registering utility window class"; - - utilWindow = CreateWindowExW(0, - utilWindowClass, L"libui utility window", - WS_OVERLAPPEDWINDOW, - 0, 0, 100, 100, - NULL, NULL, hInstance, NULL); - if (utilWindow == NULL) - return "=creating utility window"; - // and just to be safe - EnableWindow(utilWindow, FALSE); - - return NULL; -} - -void uninitUtilWindow(void) -{ - if (DestroyWindow(utilWindow) == 0) - logLastError(L"error destroying utility window"); - if (UnregisterClass(utilWindowClass, hInstance) == 0) - logLastError(L"error unregistering utility window class"); -} diff --git a/deps/libui/windows/winapi.hpp b/deps/libui/windows/winapi.hpp deleted file mode 100644 index 86aba5d7eb..0000000000 --- a/deps/libui/windows/winapi.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// 31 may 2015 -#define UNICODE -#define _UNICODE -#define STRICT -#define STRICT_TYPED_ITEMIDS - -// see https://github.com/golang/go/issues/9916#issuecomment-74812211 -// TODO get rid of this -#define INITGUID - -// for the manifest -#ifndef _UI_STATIC -#define ISOLATION_AWARE_ENABLED 1 -#endif - -// get Windows version right; right now Windows Vista -// unless otherwise stated, all values from Microsoft's sdkddkver.h -// TODO is all of this necessary? how is NTDDI_VERSION used? -// TODO plaform update sp2 -#define WINVER 0x0600 /* from Microsoft's winnls.h */ -#define _WIN32_WINNT 0x0600 -#define _WIN32_WINDOWS 0x0600 /* from Microsoft's pdh.h */ -#define _WIN32_IE 0x0700 -#define NTDDI_VERSION 0x06000000 - -#include - -// Microsoft's resource compiler will segfault if we feed it headers it was not designed to handle -#ifndef RC_INVOKED -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#endif diff --git a/deps/libui/windows/window.cpp b/deps/libui/windows/window.cpp deleted file mode 100644 index 9cf13a25e8..0000000000 --- a/deps/libui/windows/window.cpp +++ /dev/null @@ -1,533 +0,0 @@ -// 27 april 2015 -#include "uipriv_windows.hpp" - -#define windowClass L"libui_uiWindowClass" - -struct uiWindow { - uiWindowsControl c; - HWND hwnd; - HMENU menubar; - uiControl *child; - BOOL shownOnce; - int visible; - int (*onClosing)(uiWindow *, void *); - void *onClosingData; - int margined; - BOOL hasMenubar; - void (*onContentSizeChanged)(uiWindow *, void *); - void *onContentSizeChangedData; - BOOL changingSize; - int fullscreen; - WINDOWPLACEMENT fsPrevPlacement; - int borderless; -}; - -// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define windowMargin 7 - -static void windowMargins(uiWindow *w, int *mx, int *my) -{ - uiWindowsSizing sizing; - - *mx = 0; - *my = 0; - if (!w->margined) - return; - uiWindowsGetSizing(w->hwnd, &sizing); - *mx = windowMargin; - *my = windowMargin; - uiWindowsSizingDlgUnitsToPixels(&sizing, mx, my); -} - -static void windowRelayout(uiWindow *w) -{ - int x, y, width, height; - RECT r; - int mx, my; - HWND child; - - if (w->child == NULL) - return; - x = 0; - y = 0; - uiWindowsEnsureGetClientRect(w->hwnd, &r); - width = r.right - r.left; - height = r.bottom - r.top; - windowMargins(w, &mx, &my); - x += mx; - y += my; - width -= 2 * mx; - height -= 2 * my; - child = (HWND) uiControlHandle(w->child); - uiWindowsEnsureMoveWindowDuringResize(child, x, y, width, height); -} - -static LRESULT CALLBACK windowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - LONG_PTR ww; - uiWindow *w; - CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; - WINDOWPOS *wp = (WINDOWPOS *) lParam; - MINMAXINFO *mmi = (MINMAXINFO *) lParam; - int width, height; - LRESULT lResult; - - ww = GetWindowLongPtrW(hwnd, GWLP_USERDATA); - if (ww == 0) { - if (uMsg == WM_CREATE) - SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) (cs->lpCreateParams)); - // fall through to DefWindowProc() anyway - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } - w = uiWindow((void *) ww); - if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE) - return lResult; - switch (uMsg) { - case WM_COMMAND: - // not a menu - if (lParam != 0) - break; - if (HIWORD(wParam) != 0) - break; - runMenuEvent(LOWORD(wParam), uiWindow(w)); - return 0; - case WM_WINDOWPOSCHANGED: - if ((wp->flags & SWP_NOSIZE) != 0) - break; - if (w->onContentSizeChanged != NULL) // TODO figure out why this is happening too early - if (!w->changingSize) - (*(w->onContentSizeChanged))(w, w->onContentSizeChangedData); - windowRelayout(w); - return 0; - case WM_GETMINMAXINFO: - // ensure the user cannot resize the window smaller than its minimum size - lResult = DefWindowProcW(hwnd, uMsg, wParam, lParam); - uiWindowsControlMinimumSize(uiWindowsControl(w), &width, &height); - // width and height are in client coordinates; ptMinTrackSize is in window coordinates - clientSizeToWindowSize(w->hwnd, &width, &height, w->hasMenubar); - mmi->ptMinTrackSize.x = width; - mmi->ptMinTrackSize.y = height; - return lResult; - case WM_PRINTCLIENT: - // we do no special painting; just erase the background - // don't worry about the return value; we let DefWindowProcW() handle this message - SendMessageW(hwnd, WM_ERASEBKGND, wParam, lParam); - return 0; - case WM_CLOSE: - if ((*(w->onClosing))(w, w->onClosingData)) - uiControlDestroy(uiControl(w)); - return 0; // we destroyed it already - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - -ATOM registerWindowClass(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = windowClass; - wc.lpfnWndProc = windowWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - return RegisterClassW(&wc); -} - -void unregisterWindowClass(void) -{ - if (UnregisterClassW(windowClass, hInstance) == 0) - logLastError(L"error unregistering uiWindow window class"); -} - -static int defaultOnClosing(uiWindow *w, void *data) -{ - return 0; -} - -static void defaultOnPositionContentSizeChanged(uiWindow *w, void *data) -{ - // do nothing -} - -static std::map windows; - -static void uiWindowDestroy(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - // first hide ourselves - ShowWindow(w->hwnd, SW_HIDE); - // now destroy the child - if (w->child != NULL) { - uiControlSetParent(w->child, NULL); - uiControlDestroy(w->child); - } - // now free the menubar, if any - if (w->menubar != NULL) - freeMenubar(w->menubar); - // and finally free ourselves - windows.erase(w); - uiWindowsEnsureDestroyWindow(w->hwnd); - uiFreeControl(uiControl(w)); -} - -uiWindowsControlDefaultHandle(uiWindow) - -uiControl *uiWindowParent(uiControl *c) -{ - return NULL; -} - -void uiWindowSetParent(uiControl *c, uiControl *parent) -{ - uiUserBugCannotSetParentOnToplevel("uiWindow"); -} - -static int uiWindowToplevel(uiControl *c) -{ - return 1; -} - -// TODO initial state of windows is hidden; ensure this here and make it so on other platforms -static int uiWindowVisible(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - return w->visible; -} - -static void uiWindowShow(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - w->visible = 1; - // just in case the window's minimum size wasn't recalculated already - ensureMinimumWindowSize(w); - if (w->shownOnce) { - ShowWindow(w->hwnd, SW_SHOW); - return; - } - w->shownOnce = TRUE; - // make sure the child is the correct size - uiWindowsControlMinimumSizeChanged(uiWindowsControl(w)); - ShowWindow(w->hwnd, nCmdShow); - if (UpdateWindow(w->hwnd) == 0) - logLastError(L"error calling UpdateWindow() after showing uiWindow for the first time"); -} - -static void uiWindowHide(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - w->visible = 0; - ShowWindow(w->hwnd, SW_HIDE); -} - -// TODO we don't want the window to be disabled completely; that would prevent it from being moved! ...would it? -uiWindowsControlDefaultEnabled(uiWindow) -uiWindowsControlDefaultEnable(uiWindow) -uiWindowsControlDefaultDisable(uiWindow) -// TODO we need to do something about undocumented fields in the OS control types -uiWindowsControlDefaultSyncEnableState(uiWindow) -// TODO -uiWindowsControlDefaultSetParentHWND(uiWindow) - -static void uiWindowMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - uiWindow *w = uiWindow(c); - int mx, my; - - *width = 0; - *height = 0; - if (w->child != NULL) - uiWindowsControlMinimumSize(uiWindowsControl(w->child), width, height); - windowMargins(w, &mx, &my); - *width += 2 * mx; - *height += 2 * my; -} - -static void uiWindowMinimumSizeChanged(uiWindowsControl *c) -{ - uiWindow *w = uiWindow(c); - - if (uiWindowsControlTooSmall(uiWindowsControl(w))) { - // TODO figure out what to do with this function - // maybe split it into two so WM_GETMINMAXINFO can use it? - ensureMinimumWindowSize(w); - return; - } - // otherwise we only need to re-layout everything - windowRelayout(w); -} - -static void uiWindowLayoutRect(uiWindowsControl *c, RECT *r) -{ - uiWindow *w = uiWindow(c); - - // the layout rect is the client rect in this case - uiWindowsEnsureGetClientRect(w->hwnd, r); -} - -uiWindowsControlDefaultAssignControlIDZOrder(uiWindow) - -static void uiWindowChildVisibilityChanged(uiWindowsControl *c) -{ - // TODO eliminate the redundancy - uiWindowsControlMinimumSizeChanged(c); -} - -char *uiWindowTitle(uiWindow *w) -{ - return uiWindowsWindowText(w->hwnd); -} - -void uiWindowSetTitle(uiWindow *w, const char *title) -{ - uiWindowsSetWindowText(w->hwnd, title); - // don't queue resize; the caption isn't part of what affects layout and sizing of the client area (it'll be ellipsized if too long) -} - -// this is used for both fullscreening and centering -// see also https://blogs.msdn.microsoft.com/oldnewthing/20100412-00/?p=14353 and https://blogs.msdn.microsoft.com/oldnewthing/20050505-04/?p=35703 -static void windowMonitorRect(HWND hwnd, RECT *r) -{ - HMONITOR monitor; - MONITORINFO mi; - - monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); - ZeroMemory(&mi, sizeof (MONITORINFO)); - mi.cbSize = sizeof (MONITORINFO); - if (GetMonitorInfoW(monitor, &mi) == 0) { - logLastError(L"error getting window monitor rect"); - // default to SM_CXSCREEN x SM_CYSCREEN to be safe - r->left = 0; - r->top = 0; - r->right = GetSystemMetrics(SM_CXSCREEN); - r->bottom = GetSystemMetrics(SM_CYSCREEN); - return; - } - *r = mi.rcMonitor; -} - -void uiWindowContentSize(uiWindow *w, int *width, int *height) -{ - RECT r; - - uiWindowsEnsureGetClientRect(w->hwnd, &r); - *width = r.right - r.left; - *height = r.bottom - r.top; -} - -// TODO should this disallow too small? -void uiWindowSetContentSize(uiWindow *w, int width, int height) -{ - w->changingSize = TRUE; - clientSizeToWindowSize(w->hwnd, &width, &height, w->hasMenubar); - if (SetWindowPos(w->hwnd, NULL, 0, 0, width, height, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER) == 0) - logLastError(L"error resizing window"); - w->changingSize = FALSE; -} - -int uiWindowFullscreen(uiWindow *w) -{ - return w->fullscreen; -} - -void uiWindowSetFullscreen(uiWindow *w, int fullscreen) -{ - RECT r; - - if (w->fullscreen && fullscreen) - return; - if (!w->fullscreen && !fullscreen) - return; - w->fullscreen = fullscreen; - w->changingSize = TRUE; - if (w->fullscreen) { - ZeroMemory(&(w->fsPrevPlacement), sizeof (WINDOWPLACEMENT)); - w->fsPrevPlacement.length = sizeof (WINDOWPLACEMENT); - if (GetWindowPlacement(w->hwnd, &(w->fsPrevPlacement)) == 0) - logLastError(L"error getting old window placement"); - windowMonitorRect(w->hwnd, &r); - setStyle(w->hwnd, getStyle(w->hwnd) & ~WS_OVERLAPPEDWINDOW); - if (SetWindowPos(w->hwnd, HWND_TOP, - r.left, r.top, - r.right - r.left, r.bottom - r.top, - SWP_FRAMECHANGED | SWP_NOOWNERZORDER) == 0) - logLastError(L"error making window fullscreen"); - } else { - if (!w->borderless) // keep borderless until that is turned off - setStyle(w->hwnd, getStyle(w->hwnd) | WS_OVERLAPPEDWINDOW); - if (SetWindowPlacement(w->hwnd, &(w->fsPrevPlacement)) == 0) - logLastError(L"error leaving fullscreen"); - if (SetWindowPos(w->hwnd, NULL, - 0, 0, 0, 0, - SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER) == 0) - logLastError(L"error restoring window border after fullscreen"); - } - w->changingSize = FALSE; -} - -void uiWindowOnContentSizeChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data) -{ - w->onContentSizeChanged = f; - w->onContentSizeChangedData = data; -} - -void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data) -{ - w->onClosing = f; - w->onClosingData = data; -} - -int uiWindowBorderless(uiWindow *w) -{ - return w->borderless; -} - -// TODO window should move to the old client position and should not have the extra space the borders left behind -// TODO extract the relevant styles from WS_OVERLAPPEDWINDOW? -void uiWindowSetBorderless(uiWindow *w, int borderless) -{ - w->borderless = borderless; - if (w->borderless) - setStyle(w->hwnd, getStyle(w->hwnd) & ~WS_OVERLAPPEDWINDOW); - else - if (!w->fullscreen) // keep borderless until leaving fullscreen - setStyle(w->hwnd, getStyle(w->hwnd) | WS_OVERLAPPEDWINDOW); -} - -void uiWindowSetChild(uiWindow *w, uiControl *child) -{ - if (w->child != NULL) { - uiControlSetParent(w->child, NULL); - uiWindowsControlSetParentHWND(uiWindowsControl(w->child), NULL); - } - w->child = child; - if (w->child != NULL) { - uiControlSetParent(w->child, uiControl(w)); - uiWindowsControlSetParentHWND(uiWindowsControl(w->child), w->hwnd); - uiWindowsControlAssignSoleControlIDZOrder(uiWindowsControl(w->child)); - windowRelayout(w); - } -} - -int uiWindowMargined(uiWindow *w) -{ - return w->margined; -} - -void uiWindowSetMargined(uiWindow *w, int margined) -{ - w->margined = margined; - windowRelayout(w); -} - -// see http://blogs.msdn.com/b/oldnewthing/archive/2003/09/11/54885.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/09/13/54917.aspx -// TODO use clientSizeToWindowSize() -static void setClientSize(uiWindow *w, int width, int height, BOOL hasMenubar, DWORD style, DWORD exstyle) -{ - RECT window; - - window.left = 0; - window.top = 0; - window.right = width; - window.bottom = height; - if (AdjustWindowRectEx(&window, style, hasMenubar, exstyle) == 0) - logLastError(L"error getting real window coordinates"); - if (hasMenubar) { - RECT temp; - - temp = window; - temp.bottom = 0x7FFF; // infinite height - SendMessageW(w->hwnd, WM_NCCALCSIZE, (WPARAM) FALSE, (LPARAM) (&temp)); - window.bottom += temp.top; - } - if (SetWindowPos(w->hwnd, NULL, 0, 0, window.right - window.left, window.bottom - window.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER) == 0) - logLastError(L"error resizing window"); -} - -uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) -{ - uiWindow *w; - WCHAR *wtitle; - BOOL hasMenubarBOOL; - - uiWindowsNewControl(uiWindow, w); - - hasMenubarBOOL = FALSE; - if (hasMenubar) - hasMenubarBOOL = TRUE; - w->hasMenubar = hasMenubarBOOL; - -#define style WS_OVERLAPPEDWINDOW -#define exstyle 0 - - wtitle = toUTF16(title); - w->hwnd = CreateWindowExW(exstyle, - windowClass, wtitle, - style, - CW_USEDEFAULT, CW_USEDEFAULT, - // use the raw width and height for now - // this will get CW_USEDEFAULT (hopefully) predicting well - // even if it doesn't, we're adjusting it later - width, height, - NULL, NULL, hInstance, w); - if (w->hwnd == NULL) - logLastError(L"error creating window"); - uiFree(wtitle); - - if (hasMenubar) { - w->menubar = makeMenubar(); - if (SetMenu(w->hwnd, w->menubar) == 0) - logLastError(L"error giving menu to window"); - } - - // and use the proper size - setClientSize(w, width, height, hasMenubarBOOL, style, exstyle); - - uiWindowOnClosing(w, defaultOnClosing, NULL); - uiWindowOnContentSizeChanged(w, defaultOnPositionContentSizeChanged, NULL); - - windows[w] = true; - return w; -} - -// this cannot queue a resize because it's called by the resize handler -void ensureMinimumWindowSize(uiWindow *w) -{ - int width, height; - RECT r; - - uiWindowsControlMinimumSize(uiWindowsControl(w), &width, &height); - uiWindowsEnsureGetClientRect(w->hwnd, &r); - if (width < (r.right - r.left)) // preserve width if larger - width = r.right - r.left; - if (height < (r.bottom - r.top)) // preserve height if larger - height = r.bottom - r.top; - clientSizeToWindowSize(w->hwnd, &width, &height, w->hasMenubar); - if (SetWindowPos(w->hwnd, NULL, 0, 0, width, height, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER) == 0) - logLastError(L"error resizing window"); -} - -void disableAllWindowsExcept(uiWindow *which) -{ - for (auto &w : windows) { - if (w.first == which) - continue; - EnableWindow(w.first->hwnd, FALSE); - } -} - -void enableAllWindowsExcept(uiWindow *which) -{ - for (auto &w : windows) { - if (w.first == which) - continue; - if (!uiControlEnabled(uiControl(w.first))) - continue; - EnableWindow(w.first->hwnd, TRUE); - } -} diff --git a/deps/libui/windows/winpublic.cpp b/deps/libui/windows/winpublic.cpp deleted file mode 100644 index 397a3b54c9..0000000000 --- a/deps/libui/windows/winpublic.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.hpp" - -void uiWindowsEnsureDestroyWindow(HWND hwnd) -{ - if (DestroyWindow(hwnd) == 0) - logLastError(L"error destroying window"); -} - -void uiWindowsEnsureSetParentHWND(HWND hwnd, HWND parent) -{ - if (parent == NULL) - parent = utilWindow; - if (SetParent(hwnd, parent) == 0) - logLastError(L"error setting window parent"); -} - -void uiWindowsEnsureAssignControlIDZOrder(HWND hwnd, LONG_PTR *controlID, HWND *insertAfter) -{ - SetWindowLongPtrW(hwnd, GWLP_ID, *controlID); - (*controlID)++; - setWindowInsertAfter(hwnd, *insertAfter); - *insertAfter = hwnd; -} - -void uiWindowsEnsureMoveWindowDuringResize(HWND hwnd, int x, int y, int width, int height) -{ - RECT r; - - r.left = x; - r.top = y; - r.right = x + width; - r.bottom = y + height; - if (SetWindowPos(hwnd, NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER) == 0) - logLastError(L"error moving window"); -} - -// do these function even error out in any case other than invalid parameters?! I thought all windows had rects -void uiWindowsEnsureGetClientRect(HWND hwnd, RECT *r) -{ - if (GetClientRect(hwnd, r) == 0) { - logLastError(L"error getting window client rect"); - // zero out the rect on error just to be safe - r->left = 0; - r->top = 0; - r->right = 0; - r->bottom = 0; - } -} - -void uiWindowsEnsureGetWindowRect(HWND hwnd, RECT *r) -{ - if (GetWindowRect(hwnd, r) == 0) { - logLastError(L"error getting window rect"); - // zero out the rect on error just to be safe - r->left = 0; - r->top = 0; - r->right = 0; - r->bottom = 0; - } -} diff --git a/deps/libui/windows/winutil.cpp b/deps/libui/windows/winutil.cpp deleted file mode 100644 index 507c5a3f71..0000000000 --- a/deps/libui/windows/winutil.cpp +++ /dev/null @@ -1,154 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.hpp" - -// this is a helper function that takes the logic of determining window classes and puts it all in one place -// there are a number of places where we need to know what window class an arbitrary handle has -// theoretically we could use the class atom to avoid a _wcsicmp() -// however, raymond chen advises against this - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/11/240744.aspx (and we're not in control of the Tab class, before you say anything) -// usage: windowClassOf(hwnd, L"class 1", L"class 2", ..., NULL) -int windowClassOf(HWND hwnd, ...) -{ -// MSDN says 256 is the maximum length of a class name; add a few characters just to be safe (because it doesn't say whether this includes the terminating null character) -#define maxClassName 260 - WCHAR classname[maxClassName + 1]; - va_list ap; - WCHAR *curname; - int i; - - if (GetClassNameW(hwnd, classname, maxClassName) == 0) { - logLastError(L"error getting name of window class"); - // assume no match on error, just to be safe - return -1; - } - va_start(ap, hwnd); - i = 0; - for (;;) { - curname = va_arg(ap, WCHAR *); - if (curname == NULL) - break; - if (_wcsicmp(classname, curname) == 0) { - va_end(ap); - return i; - } - i++; - } - // no match - va_end(ap); - return -1; -} - -// wrapper around MapWindowRect() that handles the complex error handling -void mapWindowRect(HWND from, HWND to, RECT *r) -{ - RECT prevr; - DWORD le; - - prevr = *r; - SetLastError(0); - if (MapWindowRect(from, to, r) == 0) { - le = GetLastError(); - SetLastError(le); // just to be safe - if (le != 0) { - logLastError(L"error calling MapWindowRect()"); - // restore original rect on error, just in case - *r = prevr; - } - } -} - -DWORD getStyle(HWND hwnd) -{ - return (DWORD) GetWindowLongPtrW(hwnd, GWL_STYLE); -} - -void setStyle(HWND hwnd, DWORD style) -{ - SetWindowLongPtrW(hwnd, GWL_STYLE, (LONG_PTR) style); -} - -DWORD getExStyle(HWND hwnd) -{ - return (DWORD) GetWindowLongPtrW(hwnd, GWL_EXSTYLE); -} - -void setExStyle(HWND hwnd, DWORD exstyle) -{ - SetWindowLongPtrW(hwnd, GWL_EXSTYLE, (LONG_PTR) exstyle); -} - -// see http://blogs.msdn.com/b/oldnewthing/archive/2003/09/11/54885.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/09/13/54917.aspx -void clientSizeToWindowSize(HWND hwnd, int *width, int *height, BOOL hasMenubar) -{ - RECT window; - - window.left = 0; - window.top = 0; - window.right = *width; - window.bottom = *height; - if (AdjustWindowRectEx(&window, getStyle(hwnd), hasMenubar, getExStyle(hwnd)) == 0) { - logLastError(L"error getting adjusted window rect"); - // on error, don't give up; the window will be smaller but whatever - window.left = 0; - window.top = 0; - window.right = *width; - window.bottom = *height; - } - if (hasMenubar) { - RECT temp; - - temp = window; - temp.bottom = 0x7FFF; // infinite height - SendMessageW(hwnd, WM_NCCALCSIZE, (WPARAM) FALSE, (LPARAM) (&temp)); - window.bottom += temp.top; - } - *width = window.right - window.left; - *height = window.bottom - window.top; -} - -HWND parentOf(HWND child) -{ - return GetAncestor(child, GA_PARENT); -} - -HWND parentToplevel(HWND child) -{ - return GetAncestor(child, GA_ROOT); -} - -void setWindowInsertAfter(HWND hwnd, HWND insertAfter) -{ - if (SetWindowPos(hwnd, insertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE) == 0) - logLastError(L"error reordering window"); -} - -HWND getDlgItem(HWND hwnd, int id) -{ - HWND out; - - out = GetDlgItem(hwnd, id); - if (out == NULL) - logLastError(L"error getting dialog item handle"); - return out; -} - -void invalidateRect(HWND hwnd, RECT *r, BOOL erase) -{ - if (InvalidateRect(hwnd, r, erase) == 0) - logLastError(L"error invalidating window rect"); -} - -// that damn ABI bug is never going to escape me is it -D2D1_SIZE_F realGetSize(ID2D1RenderTarget *rt) -{ -#ifdef _MSC_VER - return rt->GetSize(); -#else - D2D1_SIZE_F size; - typedef D2D1_SIZE_F *(__stdcall ID2D1RenderTarget::* GetSizeF)(D2D1_SIZE_F *); - GetSizeF gs; - - gs = (GetSizeF) (&(rt->GetSize)); - (rt->*gs)(&size); - return size; -#endif -} diff --git a/retroarch.c b/retroarch.c index 04ceb7c547..90823fe9f3 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2594,11 +2594,7 @@ static enum runloop_state runloop_check_state( current_input, RARCH_GRAB_MOUSE_TOGGLE); if (pressed && !old_pressed) -#if HAVE_LIBUI - command_event(CMD_EVENT_LIBUI_TEST, NULL); -#else command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); -#endif old_pressed = pressed; } From cfd15687d1b11d8244baec717678695c6ed03936 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 16 Aug 2018 22:01:24 +0200 Subject: [PATCH 054/182] Buildfix --- Makefile.common | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.common b/Makefile.common index 27a86a6d1c..647e1e6c3b 100644 --- a/Makefile.common +++ b/Makefile.common @@ -462,6 +462,7 @@ OBJS_TLS = deps/mbedtls/debug.o \ OBJ += $(OBJS_TLS_CRYPTO) $(OBJS_TLS_X509) $(OBJS_TLS) endif +endif # Miscellaneous From 6ef3567ea5ed2f0a653e0abb63c3d24391b032ab Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 16 Aug 2018 22:48:07 -0400 Subject: [PATCH 055/182] Qt: reset shader params window when passes are set to 0 --- ui/drivers/ui_qt.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index 4e679cfeae..00c9d466fa 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -631,8 +631,26 @@ static void ui_companion_qt_event_command(void *data, enum event_command cmd) switch (cmd) { case CMD_EVENT_SHADERS_APPLY_CHANGES: - /* PRESET_LOADED already fires in more situations than APPLY_CHANGES, use that for reloading the params window */ + { + /* If shader was turned off, reload the params window manually because PRESET_LOADED won't be fired */ + video_shader_ctx_t shader_info = {0}; + + if (!video_shader_driver_get_current_shader(&shader_info)) + break; + + /* Isn't there a better way to do this? */ + if (shader_info.data && shader_info.data->num_parameters == 0) + { + if (shader_info.data->passes == 1 && string_is_empty(shader_info.data->pass[0].source.path)) + { + RARCH_LOG("[Qt]: Clearing shader parameters.\n"); + win_handle->qtWindow->deferReloadShaderParams(); + } + } + + /* Otherwise, PRESET_LOADED fires in more situations than APPLY_CHANGES, so use that for reloading the params window */ break; + } case CMD_EVENT_SHADER_PRESET_LOADED: RARCH_LOG("[Qt]: Reloading shader parameters.\n"); win_handle->qtWindow->deferReloadShaderParams(); From 648705154e85a3bf6c59aaa1086cf6e2aec1b349 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 16 Aug 2018 22:48:31 -0400 Subject: [PATCH 056/182] Qt: split functions into separate files --- Makefile.common | 16 +- griffin/griffin_cpp.cpp | 7 + menu/menu_displaylist.h | 2 + ui/drivers/qt/coreinfodialog.cpp | 96 ++ ui/drivers/qt/coreinfodialog.h | 21 + ui/drivers/qt/filedropwidget.cpp | 69 + ui/drivers/qt/filedropwidget.h | 26 + ui/drivers/qt/playlist.cpp | 1149 ++++++++++++++ ui/drivers/qt/playlistentrydialog.cpp | 259 +++ ui/drivers/qt/playlistentrydialog.h | 39 + ui/drivers/qt/shaderparamsdialog.cpp | 27 + ui/drivers/qt/shaderparamsdialog.h | 23 + ui/drivers/qt/ui_qt_window.cpp | 2105 +------------------------ ui/drivers/qt/updateretroarch.cpp | 355 +++++ ui/drivers/qt/viewoptionsdialog.cpp | 218 +++ ui/drivers/qt/viewoptionsdialog.h | 49 + ui/drivers/ui_qt.cpp | 3 + ui/drivers/ui_qt.h | 111 +- 18 files changed, 2387 insertions(+), 2188 deletions(-) create mode 100644 ui/drivers/qt/coreinfodialog.cpp create mode 100644 ui/drivers/qt/coreinfodialog.h create mode 100644 ui/drivers/qt/filedropwidget.cpp create mode 100644 ui/drivers/qt/filedropwidget.h create mode 100644 ui/drivers/qt/playlist.cpp create mode 100644 ui/drivers/qt/playlistentrydialog.cpp create mode 100644 ui/drivers/qt/playlistentrydialog.h create mode 100644 ui/drivers/qt/shaderparamsdialog.cpp create mode 100644 ui/drivers/qt/shaderparamsdialog.h create mode 100644 ui/drivers/qt/updateretroarch.cpp create mode 100644 ui/drivers/qt/viewoptionsdialog.cpp create mode 100644 ui/drivers/qt/viewoptionsdialog.h diff --git a/Makefile.common b/Makefile.common index 647e1e6c3b..7721c15c32 100644 --- a/Makefile.common +++ b/Makefile.common @@ -339,11 +339,23 @@ OBJ += ui/drivers/ui_qt.o \ ui/drivers/qt/ui_qt_browser_window.o \ ui/drivers/qt/ui_qt_load_core_window.o \ ui/drivers/qt/ui_qt_msg_window.o \ - ui/drivers/qt/flowlayout.o + ui/drivers/qt/flowlayout.o \ + ui/drivers/qt/shaderparamsdialog.o \ + ui/drivers/qt/filedropwidget.o \ + ui/drivers/qt/coreinfodialog.o \ + ui/drivers/qt/playlistentrydialog.o \ + ui/drivers/qt/viewoptionsdialog.o \ + ui/drivers/qt/playlist.o \ + ui/drivers/qt/updateretroarch.o MOC_HEADERS += ui/drivers/ui_qt.h \ ui/drivers/qt/ui_qt_load_core_window.h \ - ui/drivers/qt/flowlayout.h + ui/drivers/qt/flowlayout.h \ + ui/drivers/qt/shaderparamsdialog.h \ + ui/drivers/qt/filedropwidget.h \ + ui/drivers/qt/coreinfodialog.h \ + ui/drivers/qt/playlistentrydialog.h \ + ui/drivers/qt/viewoptionsdialog.h DEFINES += $(QT5CORE_CFLAGS) $(QT5GUI_CFLAGS) $(QT5WIDGETS_CFLAGS) $(QT5CONCURRENT_CFLAGS) $(QT5NETWORK_CFLAGS) -DHAVE_MAIN #DEFINES += $(QT5WEBENGINE_CFLAGS) diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index 17aae41d3d..a51280b7bf 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -42,6 +42,13 @@ UI #include "../ui/drivers/qt/ui_qt_msg_window.cpp" #include "../ui/drivers/qt/ui_qt_application.cpp" #include "../ui/drivers/qt/flowlayout.cpp" +#include "../ui/drivers/qt/shaderparamsdialog.cpp" +#include "../ui/drivers/qt/filedropwidget.cpp" +#include "../ui/drivers/qt/coreinfodialog.cpp" +#include "../ui/drivers/qt/playlistentrydialog.cpp" +#include "../ui/drivers/qt/viewoptionsdialog.cpp" +#include "../ui/drivers/qt/playlist.cpp" +#include "../ui/drivers/qt/updateretroarch.cpp" #endif /*============================================================ diff --git a/menu/menu_displaylist.h b/menu/menu_displaylist.h index 8fe0bea1a7..0109486219 100644 --- a/menu/menu_displaylist.h +++ b/menu/menu_displaylist.h @@ -23,6 +23,8 @@ #include #include +#include "../setting_list.h" + #ifndef COLLECTION_SIZE #define COLLECTION_SIZE 99999 #endif diff --git a/ui/drivers/qt/coreinfodialog.cpp b/ui/drivers/qt/coreinfodialog.cpp new file mode 100644 index 0000000000..8361bbcab9 --- /dev/null +++ b/ui/drivers/qt/coreinfodialog.cpp @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include "coreinfodialog.h" +#include "../ui_qt.h" + +extern "C" +{ +#include "../../../msg_hash.h" +} + +CoreInfoDialog::CoreInfoDialog(MainWindow *mainwindow, QWidget *parent) : + QDialog(parent) + ,m_formLayout(new QFormLayout()) + ,m_mainwindow(mainwindow) +{ + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION)); + + m_formLayout->setFormAlignment(Qt::AlignCenter); + m_formLayout->setLabelAlignment(Qt::AlignCenter); + + setLayout(new QVBoxLayout()); + + qobject_cast(layout())->addLayout(m_formLayout); + layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); + layout()->addWidget(buttonBox); +} + +void CoreInfoDialog::showCoreInfo() +{ + int row = 0; + int rowCount = m_formLayout->rowCount(); + int i = 0; + QVector > infoList = m_mainwindow->getCoreInfo(); + + if (rowCount > 0) + { + for (row = 0; row < rowCount; row++) + { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) + /* removeRow() and takeRow() was only added in 5.8! */ + m_formLayout->removeRow(0); +#else + /* something is buggy here... sometimes items appear duplicated, and other times not */ + QLayoutItem *item = m_formLayout->itemAt(0); + QWidget *w = NULL; + + if (item) + { + w = item->widget(); + + if (w) + { + QWidget *label = m_formLayout->labelForField(w); + + if (label) + delete label; + + m_formLayout->removeWidget(w); + + delete w; + } + } +#endif + } + } + + if (infoList.count() == 0) + return; + + for (i = 0; i < infoList.count(); i++) + { + const QHash &line = infoList.at(i); + QLabel *label = new QLabel(line.value("key")); + CoreInfoLabel *value = new CoreInfoLabel(line.value("value")); + QString labelStyle = line.value("label_style"); + QString valueStyle = line.value("value_style"); + + if (!labelStyle.isEmpty()) + label->setStyleSheet(labelStyle); + + if (!valueStyle.isEmpty()) + value->setStyleSheet(valueStyle); + + m_formLayout->addRow(label, value); + } + + show(); +} + diff --git a/ui/drivers/qt/coreinfodialog.h b/ui/drivers/qt/coreinfodialog.h new file mode 100644 index 0000000000..c0cb3f9f30 --- /dev/null +++ b/ui/drivers/qt/coreinfodialog.h @@ -0,0 +1,21 @@ +#ifndef COREINFODIALOG_H +#define COREINFODIALOG_H + +#include + +class QFormLayout; +class MainWindow; + +class CoreInfoDialog : public QDialog +{ + Q_OBJECT +public: + CoreInfoDialog(MainWindow *mainwindow, QWidget *parent = 0); +public slots: + void showCoreInfo(); +private: + QFormLayout *m_formLayout; + MainWindow *m_mainwindow; +}; + +#endif diff --git a/ui/drivers/qt/filedropwidget.cpp b/ui/drivers/qt/filedropwidget.cpp new file mode 100644 index 0000000000..09eaf0abed --- /dev/null +++ b/ui/drivers/qt/filedropwidget.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "filedropwidget.h" + +FileDropWidget::FileDropWidget(QWidget *parent) : + QWidget(parent) +{ + setAcceptDrops(true); +} + +void FileDropWidget::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QWidget::paintEvent(event); +} + +void FileDropWidget::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Delete) + { + event->accept(); + emit deletePressed(); + } + else + QWidget::keyPressEvent(event); +} + +void FileDropWidget::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *data = event->mimeData(); + + if (data->hasUrls()) + event->acceptProposedAction(); +} + +void FileDropWidget::dropEvent(QDropEvent *event) +{ + const QMimeData *data = event->mimeData(); + + if (data->hasUrls()) + { + QList urls = data->urls(); + QStringList files; + int i; + + for (i = 0; i < urls.count(); i++) + { + QString path(urls.at(i).toLocalFile()); + + files.append(path); + } + + emit filesDropped(files); + } +} + diff --git a/ui/drivers/qt/filedropwidget.h b/ui/drivers/qt/filedropwidget.h new file mode 100644 index 0000000000..9301d948df --- /dev/null +++ b/ui/drivers/qt/filedropwidget.h @@ -0,0 +1,26 @@ +#ifndef FILEDROPWIDGET_H +#define FILEDROPWIDGET_H + +#include + +class QDragEnterEvent; +class QDropEvent; +class QKeyEvent; +class QPaintEvent; + +class FileDropWidget : public QWidget +{ + Q_OBJECT +public: + FileDropWidget(QWidget *parent = 0); +signals: + void filesDropped(QStringList files); + void deletePressed(); +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); + void keyPressEvent(QKeyEvent *event); + void paintEvent(QPaintEvent *event); +}; + +#endif diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp new file mode 100644 index 0000000000..a3c81c3502 --- /dev/null +++ b/ui/drivers/qt/playlist.cpp @@ -0,0 +1,1149 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ui_qt.h" +#include "flowlayout.h" +#include "playlistentrydialog.h" + +extern "C" { +#include +#include +#include +#include +#include "../../../file_path_special.h" +#include "../../../playlist.h" +#include "../../../menu/menu_displaylist.h" +#include "../../../setting_list.h" +#include "../../../configuration.h" +#include "../../../core_info.h" +#include "../../../verbosity.h" +} + +inline static bool comp_hash_name_key_lower(const QHash &lhs, const QHash &rhs) +{ + return lhs.value("name").toLower() < rhs.value("name").toLower(); +} + +inline static bool comp_hash_label_key_lower(const QHash &lhs, const QHash &rhs) +{ + return lhs.value("label").toLower() < rhs.value("label").toLower(); +} + +static void addDirectoryFilesToList(QStringList &list, QDir &dir) +{ + QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name); + int i; + + for (i = 0; i < dirList.count(); i++) + { + QString path(dir.path() + "/" + dirList.at(i)); + QFileInfo fileInfo(path); + + if (fileInfo.isDir()) + { + QDir fileInfoDir(path); + + addDirectoryFilesToList(list, fileInfoDir); + continue; + } + + if (fileInfo.isFile()) + { + list.append(fileInfo.absoluteFilePath()); + } + } +} + +void MainWindow::onPlaylistFilesDropped(QStringList files) +{ + addFilesToPlaylist(files); +} + +/* Takes a list of files and folders and adds them to the currently selected playlist. Folders will have their contents added recursively. */ +void MainWindow::addFilesToPlaylist(QStringList files) +{ + QStringList list; + QString currentPlaylistPath; + QListWidgetItem *currentItem = m_listWidget->currentItem(); + QByteArray currentPlaylistArray; + QScopedPointer dialog(NULL); + PlaylistEntryDialog *playlistDialog = playlistEntryDialog(); + QHash selectedCore; + QHash itemToAdd; + QString selectedDatabase; + QString selectedName; + QString selectedPath; + const char *currentPlaylistData = NULL; + playlist_t *playlist = NULL; + int i; + + /* Assume a blank list means we will manually enter in all fields. */ + if (files.isEmpty()) + { + /* Make sure hash isn't blank, that would mean there's multiple entries to add at once. */ + itemToAdd["label"] = ""; + itemToAdd["path"] = ""; + } + else if (files.count() == 1) + { + QString path = files.at(0); + QFileInfo info(path); + + if (info.isFile()) + { + itemToAdd["label"] = info.completeBaseName(); + itemToAdd["path"] = path; + } + } + + if (currentItem) + { + currentPlaylistPath = currentItem->data(Qt::UserRole).toString(); + + if (!currentPlaylistPath.isEmpty()) + { + currentPlaylistArray = currentPlaylistPath.toUtf8(); + currentPlaylistData = currentPlaylistArray.constData(); + } + } + + if (currentPlaylistPath == ALL_PLAYLISTS_TOKEN) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + return; + } + + /* a blank itemToAdd means there will be multiple */ + if (!playlistDialog->showDialog(itemToAdd)) + return; + + selectedName = m_playlistEntryDialog->getSelectedName(); + selectedPath = m_playlistEntryDialog->getSelectedPath(); + selectedCore = m_playlistEntryDialog->getSelectedCore(); + selectedDatabase = m_playlistEntryDialog->getSelectedDatabase(); + + if (selectedDatabase.isEmpty()) + selectedDatabase = QFileInfo(currentPlaylistPath).fileName(); + else + selectedDatabase += file_path_str(FILE_PATH_LPL_EXTENSION); + + dialog.reset(new QProgressDialog(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES), "Cancel", 0, 0, this)); + dialog->setWindowModality(Qt::ApplicationModal); + + if (selectedName.isEmpty() || selectedPath.isEmpty() || + selectedDatabase.isEmpty()) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + return; + } + + if (files.isEmpty()) + files.append(selectedPath); + + for (i = 0; i < files.count(); i++) + { + QString path(files.at(i)); + QFileInfo fileInfo(path); + + if (dialog->wasCanceled()) + return; + + if (i % 25 == 0) + { + /* Needed to update progress dialog while doing a lot of stuff on the main thread. */ + qApp->processEvents(); + } + + if (fileInfo.isDir()) + { + QDir dir(path); + addDirectoryFilesToList(list, dir); + continue; + } + + if (fileInfo.isFile()) + list.append(fileInfo.absoluteFilePath()); + else if (files.count() == 1) + { + /* If adding a single file, tell user that it doesn't exist. */ + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + return; + } + } + + dialog->setLabelText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST)); + dialog->setMaximum(list.count()); + + playlist = playlist_init(currentPlaylistData, COLLECTION_SIZE); + + for (i = 0; i < list.count(); i++) + { + QString fileName = list.at(i); + QFileInfo fileInfo; + QByteArray fileBaseNameArray; + QByteArray pathArray; + QByteArray corePathArray; + QByteArray coreNameArray; + QByteArray databaseArray; + const char *pathData = NULL; + const char *fileNameNoExten = NULL; + const char *corePathData = NULL; + const char *coreNameData = NULL; + const char *databaseData = NULL; + + if (dialog->wasCanceled()) + { + playlist_free(playlist); + return; + } + + if (fileName.isEmpty()) + continue; + + fileInfo = fileName; + + if (files.count() == 1 && list.count() == 1 && i == 0) + { + fileBaseNameArray = selectedName.toUtf8(); + pathArray = QDir::toNativeSeparators(selectedPath).toUtf8(); + } + else + { + fileBaseNameArray = fileInfo.completeBaseName().toUtf8(); + pathArray = QDir::toNativeSeparators(fileName).toUtf8(); + } + + fileNameNoExten = fileBaseNameArray.constData(); + + /* a modal QProgressDialog calls processEvents() automatically in setValue() */ + dialog->setValue(i + 1); + + pathData = pathArray.constData(); + + if (selectedCore.isEmpty()) + { + corePathData = "DETECT"; + coreNameData = "DETECT"; + } + else + { + corePathArray = QDir::toNativeSeparators(selectedCore.value("core_path")).toUtf8(); + coreNameArray = selectedCore.value("core_name").toUtf8(); + corePathData = corePathArray.constData(); + coreNameData = coreNameArray.constData(); + } + + databaseArray = selectedDatabase.toUtf8(); + databaseData = databaseArray.constData(); + + if (path_is_compressed_file(pathData)) + { + struct string_list *list = file_archive_get_file_list(pathData, NULL); + + if (list) + { + if (list->size == 1) + { + /* assume archives with one file should have that file loaded directly */ + pathArray = QDir::toNativeSeparators(QString(pathData) + "#" + list->elems[0].data).toUtf8(); + pathData = pathArray.constData(); + } + + string_list_free(list); + } + } + + playlist_push(playlist, pathData, fileNameNoExten, + corePathData, coreNameData, "00000000|crc", databaseData); + } + + playlist_write_file(playlist); + playlist_free(playlist); + + reloadPlaylists(); +} + +bool MainWindow::updateCurrentPlaylistEntry(const QHash &contentHash) +{ + QString playlistPath = getCurrentPlaylistPath(); + QString path; + QString label; + QString corePath; + QString coreName; + QString dbName; + QString crc32; + QByteArray playlistPathArray; + QByteArray pathArray; + QByteArray labelArray; + QByteArray corePathArray; + QByteArray coreNameArray; + QByteArray dbNameArray; + QByteArray crc32Array; + const char *playlistPathData = NULL; + const char *pathData = NULL; + const char *labelData = NULL; + const char *corePathData = NULL; + const char *coreNameData = NULL; + const char *dbNameData = NULL; + const char *crc32Data = NULL; + playlist_t *playlist = NULL; + unsigned index = 0; + bool ok = false; + + if (playlistPath.isEmpty() || contentHash.isEmpty() || !contentHash.contains("index")) + return false; + + index = contentHash.value("index").toUInt(&ok); + + if (!ok) + return false; + + path = contentHash.value("path"); + label = contentHash.value("label"); + coreName = contentHash.value("core_name"); + corePath = contentHash.value("core_path"); + dbName = contentHash.value("db_name"); + crc32 = contentHash.value("crc32"); + + if (path.isEmpty() || + label.isEmpty() || + coreName.isEmpty() || + corePath.isEmpty() || + dbName.isEmpty() || + crc32.isEmpty() + ) + return false; + + playlistPathArray = playlistPath.toUtf8(); + pathArray = QDir::toNativeSeparators(path).toUtf8(); + labelArray = label.toUtf8(); + coreNameArray = coreName.toUtf8(); + corePathArray = QDir::toNativeSeparators(corePath).toUtf8(); + dbNameArray = (dbName + file_path_str(FILE_PATH_LPL_EXTENSION)).toUtf8(); + crc32Array = crc32.toUtf8(); + + playlistPathData = playlistPathArray.constData(); + pathData = pathArray.constData(); + labelData = labelArray.constData(); + coreNameData = coreNameArray.constData(); + corePathData = corePathArray.constData(); + dbNameData = dbNameArray.constData(); + crc32Data = crc32Array.constData(); + + if (path_is_compressed_file(pathData)) + { + struct string_list *list = file_archive_get_file_list(pathData, NULL); + + if (list) + { + if (list->size == 1) + { + /* assume archives with one file should have that file loaded directly */ + pathArray = QDir::toNativeSeparators(QString(pathData) + "#" + list->elems[0].data).toUtf8(); + pathData = pathArray.constData(); + } + + string_list_free(list); + } + } + + playlist = playlist_init(playlistPathData, COLLECTION_SIZE); + + playlist_update(playlist, index, pathData, labelData, + corePathData, coreNameData, crc32Data, dbNameData); + playlist_write_file(playlist); + playlist_free(playlist); + + reloadPlaylists(); + + return true; +} + +void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) +{ + settings_t *settings = config_get_ptr(); + QScopedPointer menu; + QScopedPointer associateMenu; + QScopedPointer hiddenPlaylistsMenu; + QScopedPointer hideAction; + QScopedPointer newPlaylistAction; + QScopedPointer deletePlaylistAction; + QPointer selectedAction; + QPoint cursorPos = QCursor::pos(); + QListWidgetItem *selectedItem = m_listWidget->itemAt(m_listWidget->viewport()->mapFromGlobal(cursorPos)); + QDir playlistDir(settings->paths.directory_playlist); + QString playlistDirAbsPath = playlistDir.absolutePath(); + QString currentPlaylistDirPath; + QString currentPlaylistPath; + QString currentPlaylistFileName; + QFile currentPlaylistFile; + QByteArray currentPlaylistFileNameArray; + QFileInfo currentPlaylistFileInfo; + QMap coreList; + core_info_list_t *core_info_list = NULL; + union string_list_elem_attr attr = {0}; + struct string_list *stnames = NULL; + struct string_list *stcores = NULL; + unsigned i = 0; + int j = 0; + size_t found = 0; + const char *currentPlaylistFileNameData = NULL; + char new_playlist_names[PATH_MAX_LENGTH]; + char new_playlist_cores[PATH_MAX_LENGTH]; + bool specialPlaylist = false; + bool foundHiddenPlaylist = false; + + new_playlist_names[0] = new_playlist_cores[0] = '\0'; + + stnames = string_split(settings->arrays.playlist_names, ";"); + stcores = string_split(settings->arrays.playlist_cores, ";"); + + if (selectedItem) + { + currentPlaylistPath = selectedItem->data(Qt::UserRole).toString(); + currentPlaylistFile.setFileName(currentPlaylistPath); + + currentPlaylistFileInfo = QFileInfo(currentPlaylistPath); + currentPlaylistFileName = currentPlaylistFileInfo.fileName(); + currentPlaylistDirPath = currentPlaylistFileInfo.absoluteDir().absolutePath(); + + currentPlaylistFileNameArray.append(currentPlaylistFileName); + currentPlaylistFileNameData = currentPlaylistFileNameArray.constData(); + } + + menu.reset(new QMenu(this)); + menu->setObjectName("menu"); + + hiddenPlaylistsMenu.reset(new QMenu(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS), this)); + newPlaylistAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST)) + "...", this)); + + hiddenPlaylistsMenu->setObjectName("hiddenPlaylistsMenu"); + + menu->addAction(newPlaylistAction.data()); + + if (currentPlaylistFile.exists()) + { + deletePlaylistAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST)) + "...", this)); + menu->addAction(deletePlaylistAction.data()); + } + + if (selectedItem) + { + hideAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_HIDE), this)); + menu->addAction(hideAction.data()); + } + + for (j = 0; j < m_listWidget->count(); j++) + { + QListWidgetItem *item = m_listWidget->item(j); + bool hidden = m_listWidget->isItemHidden(item); + + if (hidden) + { + QAction *action = hiddenPlaylistsMenu->addAction(item->text()); + action->setProperty("row", j); + action->setProperty("core_path", item->data(Qt::UserRole).toString()); + foundHiddenPlaylist = true; + } + } + + if (!foundHiddenPlaylist) + { + QAction *action = hiddenPlaylistsMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE)); + action->setProperty("row", -1); + } + + menu->addMenu(hiddenPlaylistsMenu.data()); + + if (currentPlaylistDirPath != playlistDirAbsPath) + { + /* special playlists like history etc. can't have an association */ + specialPlaylist = true; + } + + if (!specialPlaylist) + { + associateMenu.reset(new QMenu(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ASSOCIATE_CORE), this)); + associateMenu->setObjectName("associateMenu"); + + core_info_get_list(&core_info_list); + + for (i = 0; i < core_info_list->count && core_info_list->count > 0; i++) + { + const core_info_t *core = &core_info_list->list[i]; + coreList[core->core_name] = core; + } + + { + QMapIterator coreListIterator(coreList); + QVector > cores; + + while (coreListIterator.hasNext()) + { + QString key; + const core_info_t *core = NULL; + QString name; + QHash hash; + + coreListIterator.next(); + + key = coreListIterator.key(); + core = coreList.value(key); + + if (string_is_empty(core->core_name)) + name = core->display_name; + else + name = core->core_name; + + if (name.isEmpty()) + continue; + + hash["name"] = name; + hash["core_path"] = core->path; + + cores.append(hash); + } + + std::sort(cores.begin(), cores.end(), comp_hash_name_key_lower); + + for (j = 0; j < cores.count(); j++) + { + const QHash &hash = cores.at(j); + QAction *action = associateMenu->addAction(hash.value("name")); + + action->setProperty("core_path", hash.value("core_path")); + } + } + + menu->addMenu(associateMenu.data()); + } + + selectedAction = menu->exec(cursorPos); + + if (!selectedAction) + goto end; + + if (!specialPlaylist && selectedAction->parent() == associateMenu.data()) + { + found = string_list_find_elem(stnames, currentPlaylistFileNameData); + + if (found) + string_list_set(stcores, static_cast(found - 1), selectedAction->property("core_path").toString().toUtf8().constData()); + else + { + string_list_append(stnames, currentPlaylistFileNameData, attr); + string_list_append(stcores, "DETECT", attr); + + found = string_list_find_elem(stnames, currentPlaylistFileNameData); + + if (found) + string_list_set(stcores, static_cast(found - 1), selectedAction->property("core_path").toString().toUtf8().constData()); + } + + string_list_join_concat(new_playlist_names, + sizeof(new_playlist_names), stnames, ";"); + string_list_join_concat(new_playlist_cores, + sizeof(new_playlist_cores), stcores, ";"); + + strlcpy(settings->arrays.playlist_names, + new_playlist_names, sizeof(settings->arrays.playlist_names)); + strlcpy(settings->arrays.playlist_cores, + new_playlist_cores, sizeof(settings->arrays.playlist_cores)); + } + else if (selectedAction == deletePlaylistAction.data()) + { + if (currentPlaylistFile.exists()) + { + if (showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST)).arg(selectedItem->text()), MainWindow::MSGBOX_TYPE_QUESTION_YESNO, Qt::ApplicationModal, false)) + { + if (currentPlaylistFile.remove()) + reloadPlaylists(); + else + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + } + } + } + else if (selectedAction == newPlaylistAction.data()) + { + QString name = QInputDialog::getText(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST), msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME)); + QString newPlaylistPath = playlistDirAbsPath + "/" + name + file_path_str(FILE_PATH_LPL_EXTENSION); + QFile file(newPlaylistPath); + + if (file.open(QIODevice::WriteOnly)) + file.close(); + + reloadPlaylists(); + } + else if (selectedAction == hideAction.data()) + { + int row = m_listWidget->row(selectedItem); + + if (row >= 0) + { + QStringList hiddenPlaylists = m_settings->value("hidden_playlists").toStringList(); + + if (!hiddenPlaylists.contains(currentPlaylistFileName)) + { + hiddenPlaylists.append(currentPlaylistFileName); + m_settings->setValue("hidden_playlists", hiddenPlaylists); + } + + m_listWidget->setRowHidden(row, true); + } + } + else if (selectedAction->parent() == hiddenPlaylistsMenu.data()) + { + QVariant rowVariant = selectedAction->property("row"); + + if (rowVariant.isValid()) + { + QStringList hiddenPlaylists = m_settings->value("hidden_playlists").toStringList(); + int row = rowVariant.toInt(); + + if (row >= 0) + { + QString playlistPath = selectedAction->property("core_path").toString(); + QFileInfo playlistFileInfo(playlistPath); + QString playlistFileName = playlistFileInfo.fileName(); + + if (hiddenPlaylists.contains(playlistFileName)) + { + hiddenPlaylists.removeOne(playlistFileName); + m_settings->setValue("hidden_playlists", hiddenPlaylists); + } + + m_listWidget->setRowHidden(row, false); + } + } + } + + setCoreActions(); + +end: + if (stnames) + string_list_free(stnames); + if (stcores) + string_list_free(stcores); +} + +void MainWindow::deferReloadPlaylists() +{ + emit gotReloadPlaylists(); +} + +void MainWindow::onGotReloadPlaylists() +{ + reloadPlaylists(); +} + +void MainWindow::reloadPlaylists() +{ + QListWidgetItem *allPlaylistsItem = NULL; + QListWidgetItem *favoritesPlaylistsItem = NULL; + QListWidgetItem *imagePlaylistsItem = NULL; + QListWidgetItem *musicPlaylistsItem = NULL; + QListWidgetItem *videoPlaylistsItem = NULL; + QListWidgetItem *firstItem = NULL; + QListWidgetItem *currentItem = NULL; + settings_t *settings = config_get_ptr(); + QDir playlistDir(settings->paths.directory_playlist); + QString currentPlaylistPath; + QStringList hiddenPlaylists = m_settings->value("hidden_playlists").toStringList(); + int i = 0; + + currentItem = m_listWidget->currentItem(); + + if (currentItem) + { + currentPlaylistPath = currentItem->data(Qt::UserRole).toString(); + } + + getPlaylistFiles(); + + m_listWidget->clear(); + + allPlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS)); + allPlaylistsItem->setData(Qt::UserRole, ALL_PLAYLISTS_TOKEN); + + favoritesPlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES_TAB)); + favoritesPlaylistsItem->setData(Qt::UserRole, settings->paths.path_content_favorites); + + m_historyPlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_HISTORY_TAB)); + m_historyPlaylistsItem->setData(Qt::UserRole, settings->paths.path_content_history); + + imagePlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_IMAGES_TAB)); + imagePlaylistsItem->setData(Qt::UserRole, settings->paths.path_content_image_history); + + musicPlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MUSIC_TAB)); + musicPlaylistsItem->setData(Qt::UserRole, settings->paths.path_content_music_history); + + videoPlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_TAB)); + videoPlaylistsItem->setData(Qt::UserRole, settings->paths.path_content_video_history); + + m_listWidget->addItem(allPlaylistsItem); + m_listWidget->addItem(favoritesPlaylistsItem); + m_listWidget->addItem(m_historyPlaylistsItem); + m_listWidget->addItem(imagePlaylistsItem); + m_listWidget->addItem(musicPlaylistsItem); + m_listWidget->addItem(videoPlaylistsItem); + + if (hiddenPlaylists.contains(ALL_PLAYLISTS_TOKEN)) + m_listWidget->setRowHidden(m_listWidget->row(allPlaylistsItem), true); + if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_favorites).fileName())) + m_listWidget->setRowHidden(m_listWidget->row(favoritesPlaylistsItem), true); + if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_history).fileName())) + m_listWidget->setRowHidden(m_listWidget->row(m_historyPlaylistsItem), true); + if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_image_history).fileName())) + m_listWidget->setRowHidden(m_listWidget->row(imagePlaylistsItem), true); + if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_music_history).fileName())) + m_listWidget->setRowHidden(m_listWidget->row(musicPlaylistsItem), true); + if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_video_history).fileName())) + m_listWidget->setRowHidden(m_listWidget->row(videoPlaylistsItem), true); + + for (i = 0; i < m_playlistFiles.count(); i++) + { + QListWidgetItem *item = NULL; + const QString &file = m_playlistFiles.at(i); + QString fileDisplayName = file; + QString fileName = file; + bool hasIcon = false; + QIcon icon; + QString iconPath; + + fileDisplayName.remove(file_path_str(FILE_PATH_LPL_EXTENSION)); + + iconPath = QString(settings->paths.directory_assets) + ICON_PATH + fileDisplayName + ".png"; + + hasIcon = QFile::exists(iconPath); + + if (hasIcon) + icon = QIcon(iconPath); + else + icon = m_folderIcon; + + item = new QListWidgetItem(icon, fileDisplayName); + item->setData(Qt::UserRole, playlistDir.absoluteFilePath(file)); + + m_listWidget->addItem(item); + + if (hiddenPlaylists.contains(fileName)) + { + int row = m_listWidget->row(item); + + if (row >= 0) + m_listWidget->setRowHidden(row, true); + } + } + + if (m_listWidget->count() > 0) + { + firstItem = m_listWidget->item(0); + + if (firstItem) + { + bool found = false; + + for (i = 0; i < m_listWidget->count(); i++) + { + QListWidgetItem *item = m_listWidget->item(i); + QString path; + + if (item) + { + path = item->data(Qt::UserRole).toString(); + + if (!currentPlaylistPath.isEmpty() && !path.isEmpty()) + { + if (path == currentPlaylistPath) + { + found = true; + m_listWidget->setCurrentItem(item); + break; + } + } + } + } + + /* the previous playlist must be gone now, just select the first one */ + if (!found) + m_listWidget->setCurrentItem(firstItem); + } + } +} + +QString MainWindow::getCurrentPlaylistPath() +{ + QListWidgetItem *playlistItem = m_listWidget->currentItem(); + QHash contentHash; + QString playlistPath; + + if (!playlistItem) + return playlistPath; + + playlistPath = playlistItem->data(Qt::UserRole).toString(); + + return playlistPath; +} + +void MainWindow::deleteCurrentPlaylistItem() +{ + QString playlistPath = getCurrentPlaylistPath(); + QByteArray playlistArray; + QHash contentHash = getCurrentContentHash(); + playlist_t *playlist = NULL; + const char *playlistData = NULL; + unsigned index = 0; + bool ok = false; + + if (playlistPath.isEmpty()) + return; + + if (contentHash.isEmpty()) + return; + + playlistArray = playlistPath.toUtf8(); + playlistData = playlistArray.constData(); + + index = contentHash.value("index").toUInt(&ok); + + if (!ok) + return; + + if (!showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM)).arg(contentHash["label"]), MainWindow::MSGBOX_TYPE_QUESTION_YESNO, Qt::ApplicationModal, false)) + return; + + playlist = playlist_init(playlistData, COLLECTION_SIZE); + + playlist_delete_index(playlist, index); + playlist_write_file(playlist); + playlist_free(playlist); + + reloadPlaylists(); +} + +QVector > MainWindow::getPlaylistDefaultCores() +{ + settings_t *settings = config_get_ptr(); + struct string_list *playlists = string_split(settings->arrays.playlist_names, ";"); + struct string_list *cores = string_split(settings->arrays.playlist_cores, ";"); + unsigned i = 0; + QVector > coreList; + + if (!playlists || !cores) + { + RARCH_WARN("[Qt]: Could not parse one of playlist_names or playlist_cores\n"); + goto finish; + } + else if (playlists->size != cores->size) + { + RARCH_WARN("[Qt]: playlist_names array size differs from playlist_cores\n"); + goto finish; + } + + if (playlists->size == 0) + goto finish; + + for (i = 0; i < playlists->size; i++) + { + const char *playlist = playlists->elems[i].data; + const char *core = cores->elems[i].data; + QHash hash; + + hash["playlist_filename"] = playlist; + hash["playlist_filename"].remove(file_path_str(FILE_PATH_LPL_EXTENSION)); + hash["core_path"] = core; + + coreList.append(hash); + } + +finish: + if (playlists) + string_list_free(playlists); + if (cores) + string_list_free(cores); + + return coreList; +} + +void MainWindow::getPlaylistFiles() +{ + settings_t *settings = config_get_ptr(); + QDir playlistDir(settings->paths.directory_playlist); + + m_playlistFiles = playlistDir.entryList(QDir::NoDotAndDotDot | QDir::Readable | QDir::Files, QDir::Name); +} + +void MainWindow::addPlaylistItemsToGrid(const QStringList &paths, bool add) +{ + QVector > items; + int i; + + if (paths.isEmpty()) + return; + + for (i = 0; i < paths.size(); i++) + { + int j; + QVector > vec = getPlaylistItems(paths.at(i)); + /* QVector::append() wasn't added until 5.5, so just do it the old fashioned way */ + for (j = 0; j < vec.size(); j++) + { + if (add && m_allPlaylistsGridMaxCount > 0 && items.size() >= m_allPlaylistsGridMaxCount) + goto finish; + + items.append(vec.at(j)); + } + } +finish: + std::sort(items.begin(), items.end(), comp_hash_label_key_lower); + + addPlaylistHashToGrid(items); +} + +void MainWindow::addPlaylistHashToGrid(const QVector > &items) +{ + QScreen *screen = qApp->primaryScreen(); + QSize screenSize = screen->size(); + QListWidgetItem *currentItem = m_listWidget->currentItem(); + settings_t *settings = config_get_ptr(); + int i = 0; + int zoomValue = m_zoomSlider->value(); + + m_gridProgressBar->setMinimum(0); + m_gridProgressBar->setMaximum(qMax(0, items.count() - 1)); + m_gridProgressBar->setValue(0); + + for (i = 0; i < items.count(); i++) + { + const QHash &hash = items.at(i); + QPointer item; + QPointer label; + QString thumbnailFileNameNoExt; + QLabel *newLabel = NULL; + QSize thumbnailWidgetSizeHint(screenSize.width() / 8, screenSize.height() / 8); + QByteArray extension; + QString extensionStr; + QString imagePath; + int lastIndex = -1; + + if (m_listWidget->currentItem() != currentItem) + { + /* user changed the current playlist before we finished loading... abort */ + m_gridProgressWidget->hide(); + break; + } + + item = new GridItem(); + + lastIndex = hash["path"].lastIndexOf('.'); + + if (lastIndex >= 0) + { + extensionStr = hash["path"].mid(lastIndex + 1); + + if (!extensionStr.isEmpty()) + { + extension = extensionStr.toLower().toUtf8(); + } + } + + if (!extension.isEmpty() && m_imageFormats.contains(extension)) + { + /* use thumbnail widgets to show regular image files */ + imagePath = hash["path"]; + } + else + { + thumbnailFileNameNoExt = hash["label_noext"]; + thumbnailFileNameNoExt.replace(m_fileSanitizerRegex, "_"); + imagePath = QString(settings->paths.directory_thumbnails) + "/" + hash.value("db_name") + "/" + THUMBNAIL_BOXART + "/" + thumbnailFileNameNoExt + ".png"; + } + + item->hash = hash; + item->widget = new ThumbnailWidget(); + item->widget->setSizeHint(thumbnailWidgetSizeHint); + item->widget->setFixedSize(item->widget->sizeHint()); + item->widget->setLayout(new QVBoxLayout()); + item->widget->setObjectName("thumbnailWidget"); + item->widget->setProperty("hash", QVariant::fromValue >(hash)); + + connect(item->widget, SIGNAL(mouseDoubleClicked()), this, SLOT(onGridItemDoubleClicked())); + connect(item->widget, SIGNAL(mousePressed()), this, SLOT(onGridItemClicked())); + + label = new ThumbnailLabel(item->widget); + label->setObjectName("thumbnailGridLabel"); + + item->label = label; + item->labelText = hash.value("label"); + + newLabel = new QLabel(item->labelText, item->widget); + newLabel->setObjectName("thumbnailQLabel"); + newLabel->setAlignment(Qt::AlignCenter); + newLabel->setToolTip(item->labelText); + + calcGridItemSize(item, zoomValue); + + item->widget->layout()->addWidget(label); + + item->widget->layout()->addWidget(newLabel); + qobject_cast(item->widget->layout())->setStretchFactor(label, 1); + + m_gridLayout->addWidgetDeferred(item->widget); + m_gridItems.append(item); + + loadImageDeferred(item, imagePath); + + if (i % 25 == 0) + { + /* Needed to update progress dialog while doing a lot of stuff on the main thread. */ + qApp->processEvents(); + } + + m_gridProgressBar->setValue(i); + } + + /* If there's only one entry, a min/max/value of all zero would make an indeterminate progress bar that never ends... so just hide it when we are done. */ + if (m_gridProgressBar->value() == m_gridProgressBar->maximum()) + m_gridProgressWidget->hide(); +} + +QVector > MainWindow::getPlaylistItems(QString pathString) +{ + QByteArray pathArray; + QVector > items; + const char *pathData = NULL; + playlist_t *playlist = NULL; + unsigned playlistSize = 0; + unsigned i = 0; + + pathArray.append(pathString); + pathData = pathArray.constData(); + + playlist = playlist_init(pathData, COLLECTION_SIZE); + playlistSize = playlist_get_size(playlist); + + for (i = 0; i < playlistSize; i++) + { + const char *path = NULL; + const char *label = NULL; + const char *core_path = NULL; + const char *core_name = NULL; + const char *crc32 = NULL; + const char *db_name = NULL; + QHash hash; + + playlist_get_index(playlist, i, + &path, &label, &core_path, + &core_name, &crc32, &db_name); + + if (string_is_empty(path)) + continue; + else + hash["path"] = path; + + hash["index"] = QString::number(i); + + if (string_is_empty(label)) + { + hash["label"] = path; + hash["label_noext"] = path; + } + else + { + hash["label"] = label; + hash["label_noext"] = label; + } + + if (!string_is_empty(core_path)) + hash["core_path"] = core_path; + + if (!string_is_empty(core_name)) + hash["core_name"] = core_name; + + if (!string_is_empty(crc32)) + hash["crc32"] = crc32; + + if (!string_is_empty(db_name)) + { + hash["db_name"] = db_name; + hash["db_name"].remove(file_path_str(FILE_PATH_LPL_EXTENSION)); + } + + items.append(hash); + } + + playlist_free(playlist); + playlist = NULL; + + return items; +} + +void MainWindow::addPlaylistItemsToTable(const QStringList &paths, bool add) +{ + QVector > items; + int i; + + if (paths.isEmpty()) + return; + + for (i = 0; i < paths.size(); i++) + { + int j; + QVector > vec = getPlaylistItems(paths.at(i)); + /* QVector::append() wasn't added until 5.5, so just do it the old fashioned way */ + for (j = 0; j < vec.size(); j++) + { + if (add && m_allPlaylistsListMaxCount > 0 && items.size() >= m_allPlaylistsListMaxCount) + goto finish; + + items.append(vec.at(j)); + } + } +finish: + addPlaylistHashToTable(items); +} + +void MainWindow::addPlaylistHashToTable(const QVector > &items) +{ + int i = 0; + int oldRowCount = m_tableWidget->rowCount(); + + m_tableWidget->setRowCount(oldRowCount + items.count()); + + for (i = 0; i < items.count(); i++) + { + QTableWidgetItem *labelItem = NULL; + const QHash &hash = items.at(i); + + labelItem = new QTableWidgetItem(hash.value("label")); + labelItem->setData(Qt::UserRole, QVariant::fromValue >(hash)); + labelItem->setFlags(labelItem->flags() & ~Qt::ItemIsEditable); + + m_tableWidget->setItem(oldRowCount + i, 0, labelItem); + } +} + +void MainWindow::setAllPlaylistsListMaxCount(int count) +{ + if (count < 1) + count = 0; + + m_allPlaylistsListMaxCount = count; +} + +void MainWindow::setAllPlaylistsGridMaxCount(int count) +{ + if (count < 1) + count = 0; + + m_allPlaylistsGridMaxCount = count; +} + diff --git a/ui/drivers/qt/playlistentrydialog.cpp b/ui/drivers/qt/playlistentrydialog.cpp new file mode 100644 index 0000000000..d28dcf4000 --- /dev/null +++ b/ui/drivers/qt/playlistentrydialog.cpp @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "playlistentrydialog.h" +#include "../ui_qt.h" + +extern "C" { +#include "../../../core_info.h" +#include "../../../file_path_special.h" +} + +inline static bool comp_string_lower(const QString &lhs, const QString &rhs) +{ + return lhs.toLower() < rhs.toLower(); +} + +inline static bool comp_hash_ui_display_name_key_lower(const QHash &lhs, const QHash &rhs) +{ + return lhs.value("ui_display_name").toLower() < rhs.value("ui_display_name").toLower(); +} + +PlaylistEntryDialog::PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent) : + QDialog(parent) + ,m_mainwindow(mainwindow) + ,m_settings(mainwindow->settings()) + ,m_nameLineEdit(new QLineEdit(this)) + ,m_pathLineEdit(new QLineEdit(this)) + ,m_coreComboBox(new QComboBox(this)) + ,m_databaseComboBox(new QComboBox(this)) +{ + QFormLayout *form = new QFormLayout(); + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + QVBoxLayout *databaseVBoxLayout = new QVBoxLayout(); + QHBoxLayout *pathHBoxLayout = new QHBoxLayout(); + QLabel *databaseLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS), this); + QToolButton *pathPushButton = new QToolButton(this); + + pathPushButton->setText("..."); + + pathHBoxLayout->addWidget(m_pathLineEdit); + pathHBoxLayout->addWidget(pathPushButton); + + databaseVBoxLayout->addWidget(m_databaseComboBox); + databaseVBoxLayout->addWidget(databaseLabel); + + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY)); + + form->setFormAlignment(Qt::AlignCenter); + form->setLabelAlignment(Qt::AlignCenter); + + setLayout(new QVBoxLayout(this)); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + connect(this, SIGNAL(accepted()), this, SLOT(onAccepted())); + connect(this, SIGNAL(rejected()), this, SLOT(onRejected())); + + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_NAME), m_nameLineEdit); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_PATH), pathHBoxLayout); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE), m_coreComboBox); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE), databaseVBoxLayout); + + qobject_cast(layout())->addLayout(form); + layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); + layout()->addWidget(buttonBox); + + connect(pathPushButton, SIGNAL(clicked()), this, SLOT(onPathClicked())); +} + +void PlaylistEntryDialog::onPathClicked() +{ + QString filePath = QFileDialog::getOpenFileName(this); + + if (filePath.isEmpty()) + return; + + m_pathLineEdit->setText(filePath); +} + +void PlaylistEntryDialog::loadPlaylistOptions() +{ + core_info_list_t *core_info_list = NULL; + const core_info_t *core_info = NULL; + unsigned i = 0; + int j = 0; + + m_nameLineEdit->clear(); + m_pathLineEdit->clear(); + m_coreComboBox->clear(); + m_databaseComboBox->clear(); + + m_coreComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CORE_SELECTION_ASK)); + m_databaseComboBox->addItem(QString("<") + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE) + ">", QFileInfo(m_mainwindow->getCurrentPlaylistPath()).fileName().remove(file_path_str(FILE_PATH_LPL_EXTENSION))); + + core_info_get_list(&core_info_list); + + if (core_info_list && core_info_list->count > 0) + { + QVector > allCores; + QStringList allDatabases; + + for (i = 0; i < core_info_list->count; i++) + { + const core_info_t *core = &core_info_list->list[i]; + QStringList databases = QString(core->databases).split("|"); + QHash hash; + QString ui_display_name; + + hash["core_name"] = core->core_name; + hash["core_display_name"] = core->display_name; + hash["core_path"] = core->path; + hash["core_databases"] = core->databases; + + ui_display_name = hash.value("core_name"); + + if (ui_display_name.isEmpty()) + ui_display_name = hash.value("core_display_name"); + if (ui_display_name.isEmpty()) + ui_display_name = QFileInfo(hash.value("core_path")).fileName(); + if (ui_display_name.isEmpty()) + continue; + + hash["ui_display_name"] = ui_display_name; + + for (j = 0; j < databases.count(); j++) + { + QString database = databases.at(j); + + if (database.isEmpty()) + continue; + + if (!allDatabases.contains(database)) + allDatabases.append(database); + } + + if (!allCores.contains(hash)) + allCores.append(hash); + } + + std::sort(allCores.begin(), allCores.end(), comp_hash_ui_display_name_key_lower); + std::sort(allDatabases.begin(), allDatabases.end(), comp_string_lower); + + for (j = 0; j < allCores.count(); j++) + { + const QHash &hash = allCores.at(j); + + m_coreComboBox->addItem(hash.value("ui_display_name"), QVariant::fromValue(hash)); + } + + for (j = 0; j < allDatabases.count(); j++) + { + QString database = allDatabases.at(j); + m_databaseComboBox->addItem(database, database); + } + } +} + +void PlaylistEntryDialog::setEntryValues(const QHash &contentHash) +{ + QString db; + QString coreName = contentHash.value("core_name"); + int foundDB = 0; + int i = 0; + + loadPlaylistOptions(); + + if (contentHash.isEmpty()) + { + m_nameLineEdit->setText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE)); + m_pathLineEdit->setText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE)); + m_nameLineEdit->setEnabled(false); + m_pathLineEdit->setEnabled(false); + } + else + { + m_nameLineEdit->setEnabled(true); + m_pathLineEdit->setEnabled(true); + m_nameLineEdit->setText(contentHash.value("label")); + m_pathLineEdit->setText(contentHash.value("path")); + } + + for (i = 0; i < m_coreComboBox->count(); i++) + { + const QHash hash = m_coreComboBox->itemData(i, Qt::UserRole).value >(); + + if (hash.isEmpty() || coreName.isEmpty()) + continue; + + if (hash.value("core_name") == coreName) + { + m_coreComboBox->setCurrentIndex(i); + break; + } + } + + db = contentHash.value("db_name"); + + if (!db.isEmpty()) + { + foundDB = m_databaseComboBox->findText(db); + + if (foundDB >= 0) + m_databaseComboBox->setCurrentIndex(foundDB); + } +} + +const QHash PlaylistEntryDialog::getSelectedCore() +{ + return m_coreComboBox->currentData(Qt::UserRole).value >(); +} + +const QString PlaylistEntryDialog::getSelectedName() +{ + return m_nameLineEdit->text(); +} + +const QString PlaylistEntryDialog::getSelectedPath() +{ + return m_pathLineEdit->text(); +} + +const QString PlaylistEntryDialog::getSelectedDatabase() +{ + return m_databaseComboBox->currentData(Qt::UserRole).toString(); +} + +void PlaylistEntryDialog::onAccepted() +{ +} + +void PlaylistEntryDialog::onRejected() +{ +} + +bool PlaylistEntryDialog::showDialog(const QHash &hash) +{ + loadPlaylistOptions(); + setEntryValues(hash); + + if (exec() == QDialog::Accepted) + return true; + + return false; +} + +void PlaylistEntryDialog::hideDialog() +{ + reject(); +} + diff --git a/ui/drivers/qt/playlistentrydialog.h b/ui/drivers/qt/playlistentrydialog.h new file mode 100644 index 0000000000..723f46304e --- /dev/null +++ b/ui/drivers/qt/playlistentrydialog.h @@ -0,0 +1,39 @@ +#ifndef PLAYLISTENTRYDIALOG_H +#define PLAYLISTENTRYDIALOG_H + +#include + +class QSettings; +class QLineEdit; +class QComboBox; +class MainWindow; + +class PlaylistEntryDialog : public QDialog +{ + Q_OBJECT +public: + PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent = 0); + const QHash getSelectedCore(); + const QString getSelectedDatabase(); + const QString getSelectedName(); + const QString getSelectedPath(); + void setEntryValues(const QHash &contentHash); +public slots: + bool showDialog(const QHash &hash = QHash()); + void hideDialog(); + void onAccepted(); + void onRejected(); +private slots: + void onPathClicked(); +private: + void loadPlaylistOptions(); + + MainWindow *m_mainwindow; + QSettings *m_settings; + QLineEdit *m_nameLineEdit; + QLineEdit *m_pathLineEdit; + QComboBox *m_coreComboBox; + QComboBox *m_databaseComboBox; +}; + +#endif diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp new file mode 100644 index 0000000000..43dc6876ce --- /dev/null +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -0,0 +1,27 @@ +#include +#include +#include "shaderparamsdialog.h" + +ShaderParamsDialog::ShaderParamsDialog(QWidget *parent) : + QDialog(parent) +{ +} + +ShaderParamsDialog::~ShaderParamsDialog() +{ +} + +void ShaderParamsDialog::resizeEvent(QResizeEvent *event) +{ + QDialog::resizeEvent(event); + + emit resized(event->size()); +} + +void ShaderParamsDialog::closeEvent(QCloseEvent *event) +{ + QDialog::closeEvent(event); + + emit closed(); +} + diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h new file mode 100644 index 0000000000..f2b98a8118 --- /dev/null +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -0,0 +1,23 @@ +#ifndef SHADERPARAMSDIALOG_H +#define SHADERPARAMSDIALOG_H + +#include + +class QCloseEvent; +class QResizeEvent; + +class ShaderParamsDialog : public QDialog +{ + Q_OBJECT +public: + ShaderParamsDialog(QWidget *parent = 0); + ~ShaderParamsDialog(); +signals: + void closed(); + void resized(QSize size); +protected: + void closeEvent(QCloseEvent *event); + void resizeEvent(QResizeEvent *event); +}; + +#endif diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 2f09752689..44583f313a 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -40,10 +40,15 @@ #include #include "../ui_qt.h" +#include "invader_png.h" #include "ui_qt_load_core_window.h" #include "ui_qt_themes.h" #include "flowlayout.h" -#include "invader_png.h" +#include "shaderparamsdialog.h" +#include "filedropwidget.h" +#include "coreinfodialog.h" +#include "playlistentrydialog.h" +#include "viewoptionsdialog.h" extern "C" { #include "../../../version.h" @@ -57,9 +62,11 @@ extern "C" { #include "../../../file_path_special.h" #include "../../../playlist.h" #include "../../../content.h" +#ifdef HAVE_MENU #include "../../../menu/menu_driver.h" -#include "../../../tasks/tasks_internal.h" +#endif #include "../../../config.def.h" +#include "../../../tasks/tasks_internal.h" #include #include #include @@ -78,21 +85,14 @@ extern "C" { #endif #define GENERIC_FOLDER_ICON "/xmb/dot-art/png/folder.png" -#define ICON_PATH "/xmb/dot-art/png/" -#define THUMBNAIL_BOXART "Named_Boxarts" #define THUMBNAIL_SCREENSHOT "Named_Snaps" #define THUMBNAIL_TITLE "Named_Titles" -#define ALL_PLAYLISTS_TOKEN "|||ALL|||" #define HIRAGANA_START 0x3041U #define HIRAGANA_END 0x3096U #define KATAKANA_START 0x30A1U #define KATAKANA_END 0x30F6U #define HIRA_KATA_OFFSET (KATAKANA_START - HIRAGANA_START) -#define USER_AGENT "RetroArch-WIMP/1.0" #define DOCS_URL "http://docs.libretro.com/" -#define PARTIAL_EXTENSION ".partial" -#define TEMP_EXTENSION ".update_tmp" -#define RETROARCH_NIGHTLY_UPDATE_PATH "../RetroArch_update.zip" static ui_window_qt_t ui_window = {0}; @@ -105,6 +105,14 @@ enum CoreSelection CORE_SELECTION_LOAD_CORE }; +static const QPixmap getInvader() +{ + QPixmap pix; + pix.loadFromData(invader_png, invader_png_len, "PNG"); + + return pix; +} + static double lerp(double x, double y, double a, double b, double d) { return a + (b - a) * ((double)(d - x) / (double)(y - x)); } @@ -135,9 +143,9 @@ static void scan_finished_handler(void *task_data, void *user_data, const char * (void)task_data; (void)user_data; (void)err; - +#ifdef HAVE_MENU menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ); - +#endif if (!ui_window.qtWindow->settings()->value("scan_finish_confirm", true).toBool()) return; @@ -148,51 +156,6 @@ static void scan_finished_handler(void *task_data, void *user_data, const char * } #endif -inline static bool comp_string_lower(const QString &lhs, const QString &rhs) -{ - return lhs.toLower() < rhs.toLower(); -} - -inline static bool comp_hash_ui_display_name_key_lower(const QHash &lhs, const QHash &rhs) -{ - return lhs.value("ui_display_name").toLower() < rhs.value("ui_display_name").toLower(); -} - -inline static bool comp_hash_name_key_lower(const QHash &lhs, const QHash &rhs) -{ - return lhs.value("name").toLower() < rhs.value("name").toLower(); -} - -inline static bool comp_hash_label_key_lower(const QHash &lhs, const QHash &rhs) -{ - return lhs.value("label").toLower() < rhs.value("label").toLower(); -} - -static void addDirectoryFilesToList(QStringList &list, QDir &dir) -{ - QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name); - int i; - - for (i = 0; i < dirList.count(); i++) - { - QString path(dir.path() + "/" + dirList.at(i)); - QFileInfo fileInfo(path); - - if (fileInfo.isDir()) - { - QDir fileInfoDir(path); - - addDirectoryFilesToList(list, fileInfoDir); - continue; - } - - if (fileInfo.isFile()) - { - list.append(fileInfo.absoluteFilePath()); - } - } -} - /* https://gist.github.com/andrey-str/0f9c7709cbf0c9c49ef9 */ static void setElidedText(QLabel *label, QWidget *clipWidget, int padding, const QString &text) { @@ -202,31 +165,6 @@ static void setElidedText(QLabel *label, QWidget *clipWidget, int padding, const label->setText(clippedText); } -const QPixmap getInvader(); - -ShaderParamsDialog::ShaderParamsDialog(QWidget *parent) : - QDialog(parent) -{ -} - -ShaderParamsDialog::~ShaderParamsDialog() -{ -} - -void ShaderParamsDialog::resizeEvent(QResizeEvent *event) -{ - QDialog::resizeEvent(event); - - emit resized(event->size()); -} - -void ShaderParamsDialog::closeEvent(QCloseEvent *event) -{ - QDialog::closeEvent(event); - - emit closed(); -} - GridItem::GridItem() : QObject() ,widget(NULL) @@ -258,65 +196,6 @@ void TreeView::selectionChanged(const QItemSelection &selected, const QItemSelec emit itemsSelected(list); } -FileDropWidget::FileDropWidget(QWidget *parent) : - QWidget(parent) -{ - setAcceptDrops(true); -} - -void FileDropWidget::paintEvent(QPaintEvent *event) -{ - QStyleOption o; - QPainter p; - o.initFrom(this); - p.begin(this); - style()->drawPrimitive( - QStyle::PE_Widget, &o, &p, this); - p.end(); - - QWidget::paintEvent(event); -} - -void FileDropWidget::keyPressEvent(QKeyEvent *event) -{ - if (event->key() == Qt::Key_Delete) - { - event->accept(); - emit deletePressed(); - } - else - QWidget::keyPressEvent(event); -} - -void FileDropWidget::dragEnterEvent(QDragEnterEvent *event) -{ - const QMimeData *data = event->mimeData(); - - if (data->hasUrls()) - event->acceptProposedAction(); -} - -void FileDropWidget::dropEvent(QDropEvent *event) -{ - const QMimeData *data = event->mimeData(); - - if (data->hasUrls()) - { - QList urls = data->urls(); - QStringList files; - int i; - - for (i = 0; i < urls.count(); i++) - { - QString path(urls.at(i).toLocalFile()); - - files.append(path); - } - - emit filesDropped(files); - } -} - TableWidget::TableWidget(QWidget *parent) : QTableWidget(parent) { @@ -344,518 +223,6 @@ CoreInfoLabel::CoreInfoLabel(QString text, QWidget *parent) : setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); } -CoreInfoDialog::CoreInfoDialog(MainWindow *mainwindow, QWidget *parent) : - QDialog(parent) - ,m_formLayout(new QFormLayout()) - ,m_mainwindow(mainwindow) -{ - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); - - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION)); - - m_formLayout->setFormAlignment(Qt::AlignCenter); - m_formLayout->setLabelAlignment(Qt::AlignCenter); - - setLayout(new QVBoxLayout()); - - qobject_cast(layout())->addLayout(m_formLayout); - layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); - layout()->addWidget(buttonBox); -} - -void CoreInfoDialog::showCoreInfo() -{ - int row = 0; - int rowCount = m_formLayout->rowCount(); - int i = 0; - QVector > infoList = m_mainwindow->getCoreInfo(); - - if (rowCount > 0) - { - for (row = 0; row < rowCount; row++) - { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) - /* removeRow() and takeRow() was only added in 5.8! */ - m_formLayout->removeRow(0); -#else - /* something is buggy here... sometimes items appear duplicated, and other times not */ - QLayoutItem *item = m_formLayout->itemAt(0); - QWidget *w = NULL; - - if (item) - { - w = item->widget(); - - if (w) - { - QWidget *label = m_formLayout->labelForField(w); - - if (label) - delete label; - - m_formLayout->removeWidget(w); - - delete w; - } - } -#endif - } - } - - if (infoList.count() == 0) - return; - - for (i = 0; i < infoList.count(); i++) - { - const QHash &line = infoList.at(i); - QLabel *label = new QLabel(line.value("key")); - CoreInfoLabel *value = new CoreInfoLabel(line.value("value")); - QString labelStyle = line.value("label_style"); - QString valueStyle = line.value("value_style"); - - if (!labelStyle.isEmpty()) - label->setStyleSheet(labelStyle); - - if (!valueStyle.isEmpty()) - value->setStyleSheet(valueStyle); - - m_formLayout->addRow(label, value); - } - - show(); -} - -PlaylistEntryDialog::PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent) : - QDialog(parent) - ,m_mainwindow(mainwindow) - ,m_settings(mainwindow->settings()) - ,m_nameLineEdit(new QLineEdit(this)) - ,m_pathLineEdit(new QLineEdit(this)) - ,m_coreComboBox(new QComboBox(this)) - ,m_databaseComboBox(new QComboBox(this)) -{ - QFormLayout *form = new QFormLayout(); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - QVBoxLayout *databaseVBoxLayout = new QVBoxLayout(); - QHBoxLayout *pathHBoxLayout = new QHBoxLayout(); - QLabel *databaseLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS), this); - QToolButton *pathPushButton = new QToolButton(this); - - pathPushButton->setText("..."); - - pathHBoxLayout->addWidget(m_pathLineEdit); - pathHBoxLayout->addWidget(pathPushButton); - - databaseVBoxLayout->addWidget(m_databaseComboBox); - databaseVBoxLayout->addWidget(databaseLabel); - - setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY)); - - form->setFormAlignment(Qt::AlignCenter); - form->setLabelAlignment(Qt::AlignCenter); - - setLayout(new QVBoxLayout(this)); - - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - connect(this, SIGNAL(accepted()), this, SLOT(onAccepted())); - connect(this, SIGNAL(rejected()), this, SLOT(onRejected())); - - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_NAME), m_nameLineEdit); - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_PATH), pathHBoxLayout); - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE), m_coreComboBox); - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE), databaseVBoxLayout); - - qobject_cast(layout())->addLayout(form); - layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); - layout()->addWidget(buttonBox); - - connect(pathPushButton, SIGNAL(clicked()), this, SLOT(onPathClicked())); -} - -void PlaylistEntryDialog::onPathClicked() -{ - QString filePath = QFileDialog::getOpenFileName(this); - - if (filePath.isEmpty()) - return; - - m_pathLineEdit->setText(filePath); -} - -void PlaylistEntryDialog::loadPlaylistOptions() -{ - core_info_list_t *core_info_list = NULL; - const core_info_t *core_info = NULL; - unsigned i = 0; - int j = 0; - - m_nameLineEdit->clear(); - m_pathLineEdit->clear(); - m_coreComboBox->clear(); - m_databaseComboBox->clear(); - - m_coreComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CORE_SELECTION_ASK)); - m_databaseComboBox->addItem(QString("<") + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE) + ">", QFileInfo(m_mainwindow->getCurrentPlaylistPath()).fileName().remove(file_path_str(FILE_PATH_LPL_EXTENSION))); - - core_info_get_list(&core_info_list); - - if (core_info_list && core_info_list->count > 0) - { - QVector > allCores; - QStringList allDatabases; - - for (i = 0; i < core_info_list->count; i++) - { - const core_info_t *core = &core_info_list->list[i]; - QStringList databases = QString(core->databases).split("|"); - QHash hash; - QString ui_display_name; - - hash["core_name"] = core->core_name; - hash["core_display_name"] = core->display_name; - hash["core_path"] = core->path; - hash["core_databases"] = core->databases; - - ui_display_name = hash.value("core_name"); - - if (ui_display_name.isEmpty()) - ui_display_name = hash.value("core_display_name"); - if (ui_display_name.isEmpty()) - ui_display_name = QFileInfo(hash.value("core_path")).fileName(); - if (ui_display_name.isEmpty()) - continue; - - hash["ui_display_name"] = ui_display_name; - - for (j = 0; j < databases.count(); j++) - { - QString database = databases.at(j); - - if (database.isEmpty()) - continue; - - if (!allDatabases.contains(database)) - allDatabases.append(database); - } - - if (!allCores.contains(hash)) - allCores.append(hash); - } - - std::sort(allCores.begin(), allCores.end(), comp_hash_ui_display_name_key_lower); - std::sort(allDatabases.begin(), allDatabases.end(), comp_string_lower); - - for (j = 0; j < allCores.count(); j++) - { - const QHash &hash = allCores.at(j); - - m_coreComboBox->addItem(hash.value("ui_display_name"), QVariant::fromValue(hash)); - } - - for (j = 0; j < allDatabases.count(); j++) - { - QString database = allDatabases.at(j); - m_databaseComboBox->addItem(database, database); - } - } -} - -void PlaylistEntryDialog::setEntryValues(const QHash &contentHash) -{ - QString db; - QString coreName = contentHash.value("core_name"); - int foundDB = 0; - int i = 0; - - loadPlaylistOptions(); - - if (contentHash.isEmpty()) - { - m_nameLineEdit->setText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE)); - m_pathLineEdit->setText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE)); - m_nameLineEdit->setEnabled(false); - m_pathLineEdit->setEnabled(false); - } - else - { - m_nameLineEdit->setEnabled(true); - m_pathLineEdit->setEnabled(true); - m_nameLineEdit->setText(contentHash.value("label")); - m_pathLineEdit->setText(contentHash.value("path")); - } - - for (i = 0; i < m_coreComboBox->count(); i++) - { - const QHash hash = m_coreComboBox->itemData(i, Qt::UserRole).value >(); - - if (hash.isEmpty() || coreName.isEmpty()) - continue; - - if (hash.value("core_name") == coreName) - { - m_coreComboBox->setCurrentIndex(i); - break; - } - } - - db = contentHash.value("db_name"); - - if (!db.isEmpty()) - { - foundDB = m_databaseComboBox->findText(db); - - if (foundDB >= 0) - m_databaseComboBox->setCurrentIndex(foundDB); - } -} - -const QHash PlaylistEntryDialog::getSelectedCore() -{ - return m_coreComboBox->currentData(Qt::UserRole).value >(); -} - -const QString PlaylistEntryDialog::getSelectedName() -{ - return m_nameLineEdit->text(); -} - -const QString PlaylistEntryDialog::getSelectedPath() -{ - return m_pathLineEdit->text(); -} - -const QString PlaylistEntryDialog::getSelectedDatabase() -{ - return m_databaseComboBox->currentData(Qt::UserRole).toString(); -} - -void PlaylistEntryDialog::onAccepted() -{ -} - -void PlaylistEntryDialog::onRejected() -{ -} - -bool PlaylistEntryDialog::showDialog(const QHash &hash) -{ - loadPlaylistOptions(); - setEntryValues(hash); - - if (exec() == QDialog::Accepted) - return true; - - return false; -} - -void PlaylistEntryDialog::hideDialog() -{ - reject(); -} - -ViewOptionsDialog::ViewOptionsDialog(MainWindow *mainwindow, QWidget *parent) : - QDialog(parent) - ,m_mainwindow(mainwindow) - ,m_settings(mainwindow->settings()) - ,m_saveGeometryCheckBox(new QCheckBox(this)) - ,m_saveDockPositionsCheckBox(new QCheckBox(this)) - ,m_saveLastTabCheckBox(new QCheckBox(this)) - ,m_showHiddenFilesCheckBox(new QCheckBox(this)) - ,m_themeComboBox(new QComboBox(this)) - ,m_highlightColorPushButton(new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CHOOSE), this)) - ,m_highlightColor() - ,m_highlightColorLabel(new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR), this)) - ,m_customThemePath() - ,m_suggestLoadedCoreFirstCheckBox(new QCheckBox(this)) - ,m_allPlaylistsListMaxCountSpinBox(new QSpinBox(this)) - ,m_allPlaylistsGridMaxCountSpinBox(new QSpinBox(this)) -{ - QFormLayout *form = new QFormLayout(); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - - setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE)); - - m_themeComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT), MainWindow::THEME_SYSTEM_DEFAULT); - m_themeComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK), MainWindow::THEME_DARK); - m_themeComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM), MainWindow::THEME_CUSTOM); - - m_allPlaylistsListMaxCountSpinBox->setRange(0, 99999); - m_allPlaylistsGridMaxCountSpinBox->setRange(0, 99999); - - form->setFormAlignment(Qt::AlignCenter); - form->setLabelAlignment(Qt::AlignCenter); - - setLayout(new QVBoxLayout(this)); - - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - connect(this, SIGNAL(accepted()), this, SLOT(onAccepted())); - connect(this, SIGNAL(rejected()), this, SLOT(onRejected())); - - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY), m_saveGeometryCheckBox); - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS), m_saveDockPositionsCheckBox); - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB), m_saveLastTabCheckBox); - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES), m_showHiddenFilesCheckBox); - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST), m_suggestLoadedCoreFirstCheckBox); - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT), m_allPlaylistsListMaxCountSpinBox); - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT), m_allPlaylistsGridMaxCountSpinBox); - form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME), m_themeComboBox); - form->addRow(m_highlightColorLabel, m_highlightColorPushButton); - - qobject_cast(layout())->addLayout(form); - layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); - layout()->addWidget(buttonBox); - - loadViewOptions(); - - connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onThemeComboBoxIndexChanged(int))); - connect(m_highlightColorPushButton, SIGNAL(clicked()), this, SLOT(onHighlightColorChoose())); -} - -void ViewOptionsDialog::onThemeComboBoxIndexChanged(int) -{ - MainWindow::Theme theme = static_cast(m_themeComboBox->currentData(Qt::UserRole).toInt()); - - if (theme == MainWindow::THEME_CUSTOM) - { - QString filePath = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_THEME)); - - if (filePath.isEmpty()) - { - int oldThemeIndex = m_themeComboBox->findData(m_mainwindow->getThemeFromString(m_settings->value("theme", "default").toString())); - - if (m_themeComboBox->count() > oldThemeIndex) - { - disconnect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onThemeComboBoxIndexChanged(int))); - m_themeComboBox->setCurrentIndex(oldThemeIndex); - connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onThemeComboBoxIndexChanged(int))); - } - } - else - { - m_customThemePath = filePath; - - if (m_mainwindow->setCustomThemeFile(filePath)) - m_mainwindow->setTheme(theme); - } - } - else - m_mainwindow->setTheme(theme); - - showOrHideHighlightColor(); -} - -void ViewOptionsDialog::onHighlightColorChoose() -{ - QPixmap highlightPixmap(m_highlightColorPushButton->iconSize()); - QColor currentHighlightColor = m_settings->value("highlight_color", QApplication::palette().highlight().color()).value(); - QColor newHighlightColor = QColorDialog::getColor(currentHighlightColor, this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_COLOR)); - - if (newHighlightColor.isValid()) - { - MainWindow::Theme theme = static_cast(m_themeComboBox->currentData(Qt::UserRole).toInt()); - - m_highlightColor = newHighlightColor; - m_settings->setValue("highlight_color", m_highlightColor); - highlightPixmap.fill(m_highlightColor); - m_highlightColorPushButton->setIcon(highlightPixmap); - m_mainwindow->setTheme(theme); - } -} - -void ViewOptionsDialog::loadViewOptions() -{ - QColor highlightColor = m_settings->value("highlight_color", QApplication::palette().highlight().color()).value(); - QPixmap highlightPixmap(m_highlightColorPushButton->iconSize()); - int themeIndex = 0; - - m_saveGeometryCheckBox->setChecked(m_settings->value("save_geometry", false).toBool()); - m_saveDockPositionsCheckBox->setChecked(m_settings->value("save_dock_positions", false).toBool()); - m_saveLastTabCheckBox->setChecked(m_settings->value("save_last_tab", false).toBool()); - m_showHiddenFilesCheckBox->setChecked(m_settings->value("show_hidden_files", true).toBool()); - m_suggestLoadedCoreFirstCheckBox->setChecked(m_settings->value("suggest_loaded_core_first", false).toBool()); - m_allPlaylistsListMaxCountSpinBox->setValue(m_settings->value("all_playlists_list_max_count", 0).toInt()); - m_allPlaylistsGridMaxCountSpinBox->setValue(m_settings->value("all_playlists_grid_max_count", 5000).toInt()); - - themeIndex = m_themeComboBox->findData(m_mainwindow->getThemeFromString(m_settings->value("theme", "default").toString())); - - if (m_themeComboBox->count() > themeIndex) - m_themeComboBox->setCurrentIndex(themeIndex); - - if (highlightColor.isValid()) - { - m_highlightColor = highlightColor; - highlightPixmap.fill(m_highlightColor); - m_highlightColorPushButton->setIcon(highlightPixmap); - } - - showOrHideHighlightColor(); -} - -void ViewOptionsDialog::showOrHideHighlightColor() -{ - if (m_mainwindow->theme() == MainWindow::THEME_DARK) - { - m_highlightColorLabel->show(); - m_highlightColorPushButton->show(); - } - else - { - m_highlightColorLabel->hide(); - m_highlightColorPushButton->hide(); - } -} - -void ViewOptionsDialog::saveViewOptions() -{ - m_settings->setValue("save_geometry", m_saveGeometryCheckBox->isChecked()); - m_settings->setValue("save_dock_positions", m_saveDockPositionsCheckBox->isChecked()); - m_settings->setValue("save_last_tab", m_saveLastTabCheckBox->isChecked()); - m_settings->setValue("theme", m_mainwindow->getThemeString(static_cast(m_themeComboBox->currentData(Qt::UserRole).toInt()))); - m_settings->setValue("show_hidden_files", m_showHiddenFilesCheckBox->isChecked()); - m_settings->setValue("highlight_color", m_highlightColor); - m_settings->setValue("suggest_loaded_core_first", m_suggestLoadedCoreFirstCheckBox->isChecked()); - m_settings->setValue("all_playlists_list_max_count", m_allPlaylistsListMaxCountSpinBox->value()); - m_settings->setValue("all_playlists_grid_max_count", m_allPlaylistsGridMaxCountSpinBox->value()); - - if (!m_mainwindow->customThemeString().isEmpty()) - m_settings->setValue("custom_theme", m_customThemePath); - - m_mainwindow->setAllPlaylistsListMaxCount(m_allPlaylistsListMaxCountSpinBox->value()); - m_mainwindow->setAllPlaylistsGridMaxCount(m_allPlaylistsGridMaxCountSpinBox->value()); -} - -void ViewOptionsDialog::onAccepted() -{ - MainWindow::Theme newTheme = static_cast(m_themeComboBox->currentData(Qt::UserRole).toInt()); - - m_mainwindow->setTheme(newTheme); - - saveViewOptions(); -} - -void ViewOptionsDialog::onRejected() -{ - loadViewOptions(); -} - -void ViewOptionsDialog::showDialog() -{ - loadViewOptions(); - show(); -} - -void ViewOptionsDialog::hideDialog() -{ - reject(); -} - CoreInfoWidget::CoreInfoWidget(CoreInfoLabel *label, QWidget *parent) : QWidget(parent) ,m_label(label) @@ -1219,31 +586,6 @@ MainWindow::~MainWindow() removeGridItems(); } -void MainWindow::removeUpdateTempFiles() -{ - /* a QDir with no path means the current working directory */ - QDir dir; - QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name); - int i; - - for (i = 0; i < dirList.count(); i++) - { - QString path(dir.path() + "/" + dirList.at(i)); - QFile file(path); - - if (path.endsWith(TEMP_EXTENSION)) - { - QByteArray pathArray = path.toUtf8(); - const char *pathData = pathArray.constData(); - - if (file.remove()) - RARCH_LOG("[Qt]: removed temporary update file %s\n", pathData); - else - RARCH_LOG("[Qt]: could not remove temporary update file %s\n", pathData); - } - } -} - void MainWindow::onShaderParamsDialogResized(QSize size) { QVariant scrollAreaVariant = m_shaderParamsDialog->property("scrollArea"); @@ -1262,7 +604,7 @@ void MainWindow::onShaderParamsDialogResized(QSize size) void MainWindow::onShaderParamsClicked() { - video_shader_ctx_t shader_info; + video_shader_ctx_t shader_info = {0}; unsigned i; int last_pass = -1; QFormLayout *last_form = NULL; @@ -1271,7 +613,8 @@ void MainWindow::onShaderParamsClicked() QWidget *widget = NULL; QVBoxLayout *layout = NULL; - video_shader_driver_get_current_shader(&shader_info); + if (!video_shader_driver_get_current_shader(&shader_info)) + return; if (!shader_info.data || shader_info.data->num_parameters > GFX_MAX_PARAMETERS) return; @@ -1549,215 +892,6 @@ void MainWindow::onShaderParamDoubleSpinBoxValueChanged(double value) } } -void MainWindow::onPlaylistFilesDropped(QStringList files) -{ - addFilesToPlaylist(files); -} - -/* Takes a list of files and folders and adds them to the currently selected playlist. Folders will have their contents added recursively. */ -void MainWindow::addFilesToPlaylist(QStringList files) -{ - QStringList list; - QString currentPlaylistPath; - QListWidgetItem *currentItem = m_listWidget->currentItem(); - QByteArray currentPlaylistArray; - QScopedPointer dialog(NULL); - PlaylistEntryDialog *playlistDialog = playlistEntryDialog(); - QHash selectedCore; - QHash itemToAdd; - QString selectedDatabase; - QString selectedName; - QString selectedPath; - const char *currentPlaylistData = NULL; - playlist_t *playlist = NULL; - int i; - - /* Assume a blank list means we will manually enter in all fields. */ - if (files.isEmpty()) - { - /* Make sure hash isn't blank, that would mean there's multiple entries to add at once. */ - itemToAdd["label"] = ""; - itemToAdd["path"] = ""; - } - else if (files.count() == 1) - { - QString path = files.at(0); - QFileInfo info(path); - - if (info.isFile()) - { - itemToAdd["label"] = info.completeBaseName(); - itemToAdd["path"] = path; - } - } - - if (currentItem) - { - currentPlaylistPath = currentItem->data(Qt::UserRole).toString(); - - if (!currentPlaylistPath.isEmpty()) - { - currentPlaylistArray = currentPlaylistPath.toUtf8(); - currentPlaylistData = currentPlaylistArray.constData(); - } - } - - if (currentPlaylistPath == ALL_PLAYLISTS_TOKEN) - { - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - return; - } - - /* a blank itemToAdd means there will be multiple */ - if (!playlistDialog->showDialog(itemToAdd)) - return; - - selectedName = m_playlistEntryDialog->getSelectedName(); - selectedPath = m_playlistEntryDialog->getSelectedPath(); - selectedCore = m_playlistEntryDialog->getSelectedCore(); - selectedDatabase = m_playlistEntryDialog->getSelectedDatabase(); - - if (selectedDatabase.isEmpty()) - selectedDatabase = QFileInfo(currentPlaylistPath).fileName(); - else - selectedDatabase += file_path_str(FILE_PATH_LPL_EXTENSION); - - dialog.reset(new QProgressDialog(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES), "Cancel", 0, 0, this)); - dialog->setWindowModality(Qt::ApplicationModal); - - if (selectedName.isEmpty() || selectedPath.isEmpty() || - selectedDatabase.isEmpty()) - { - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - return; - } - - if (files.isEmpty()) - files.append(selectedPath); - - for (i = 0; i < files.count(); i++) - { - QString path(files.at(i)); - QFileInfo fileInfo(path); - - if (dialog->wasCanceled()) - return; - - if (i % 25 == 0) - { - /* Needed to update progress dialog while doing a lot of stuff on the main thread. */ - qApp->processEvents(); - } - - if (fileInfo.isDir()) - { - QDir dir(path); - addDirectoryFilesToList(list, dir); - continue; - } - - if (fileInfo.isFile()) - list.append(fileInfo.absoluteFilePath()); - else if (files.count() == 1) - { - /* If adding a single file, tell user that it doesn't exist. */ - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - return; - } - } - - dialog->setLabelText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST)); - dialog->setMaximum(list.count()); - - playlist = playlist_init(currentPlaylistData, COLLECTION_SIZE); - - for (i = 0; i < list.count(); i++) - { - QString fileName = list.at(i); - QFileInfo fileInfo; - QByteArray fileBaseNameArray; - QByteArray pathArray; - QByteArray corePathArray; - QByteArray coreNameArray; - QByteArray databaseArray; - const char *pathData = NULL; - const char *fileNameNoExten = NULL; - const char *corePathData = NULL; - const char *coreNameData = NULL; - const char *databaseData = NULL; - - if (dialog->wasCanceled()) - { - playlist_free(playlist); - return; - } - - if (fileName.isEmpty()) - continue; - - fileInfo = fileName; - - if (files.count() == 1 && list.count() == 1 && i == 0) - { - fileBaseNameArray = selectedName.toUtf8(); - pathArray = QDir::toNativeSeparators(selectedPath).toUtf8(); - } - else - { - fileBaseNameArray = fileInfo.completeBaseName().toUtf8(); - pathArray = QDir::toNativeSeparators(fileName).toUtf8(); - } - - fileNameNoExten = fileBaseNameArray.constData(); - - /* a modal QProgressDialog calls processEvents() automatically in setValue() */ - dialog->setValue(i + 1); - - pathData = pathArray.constData(); - - if (selectedCore.isEmpty()) - { - corePathData = "DETECT"; - coreNameData = "DETECT"; - } - else - { - corePathArray = QDir::toNativeSeparators(selectedCore.value("core_path")).toUtf8(); - coreNameArray = selectedCore.value("core_name").toUtf8(); - corePathData = corePathArray.constData(); - coreNameData = coreNameArray.constData(); - } - - databaseArray = selectedDatabase.toUtf8(); - databaseData = databaseArray.constData(); - - if (path_is_compressed_file(pathData)) - { - struct string_list *list = file_archive_get_file_list(pathData, NULL); - - if (list) - { - if (list->size == 1) - { - /* assume archives with one file should have that file loaded directly */ - pathArray = QDir::toNativeSeparators(QString(pathData) + "#" + list->elems[0].data).toUtf8(); - pathData = pathArray.constData(); - } - - string_list_free(list); - } - } - - playlist_push(playlist, pathData, fileNameNoExten, - corePathData, coreNameData, "00000000|crc", databaseData); - } - - playlist_write_file(playlist); - playlist_free(playlist); - - reloadPlaylists(); -} - void MainWindow::onGridItemClicked(ThumbnailWidget *widget) { QHash hash; @@ -2007,102 +1141,6 @@ bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowM return true; } -bool MainWindow::updateCurrentPlaylistEntry(const QHash &contentHash) -{ - QString playlistPath = getCurrentPlaylistPath(); - QString path; - QString label; - QString corePath; - QString coreName; - QString dbName; - QString crc32; - QByteArray playlistPathArray; - QByteArray pathArray; - QByteArray labelArray; - QByteArray corePathArray; - QByteArray coreNameArray; - QByteArray dbNameArray; - QByteArray crc32Array; - const char *playlistPathData = NULL; - const char *pathData = NULL; - const char *labelData = NULL; - const char *corePathData = NULL; - const char *coreNameData = NULL; - const char *dbNameData = NULL; - const char *crc32Data = NULL; - playlist_t *playlist = NULL; - unsigned index = 0; - bool ok = false; - - if (playlistPath.isEmpty() || contentHash.isEmpty() || !contentHash.contains("index")) - return false; - - index = contentHash.value("index").toUInt(&ok); - - if (!ok) - return false; - - path = contentHash.value("path"); - label = contentHash.value("label"); - coreName = contentHash.value("core_name"); - corePath = contentHash.value("core_path"); - dbName = contentHash.value("db_name"); - crc32 = contentHash.value("crc32"); - - if (path.isEmpty() || - label.isEmpty() || - coreName.isEmpty() || - corePath.isEmpty() || - dbName.isEmpty() || - crc32.isEmpty() - ) - return false; - - playlistPathArray = playlistPath.toUtf8(); - pathArray = QDir::toNativeSeparators(path).toUtf8(); - labelArray = label.toUtf8(); - coreNameArray = coreName.toUtf8(); - corePathArray = QDir::toNativeSeparators(corePath).toUtf8(); - dbNameArray = (dbName + file_path_str(FILE_PATH_LPL_EXTENSION)).toUtf8(); - crc32Array = crc32.toUtf8(); - - playlistPathData = playlistPathArray.constData(); - pathData = pathArray.constData(); - labelData = labelArray.constData(); - coreNameData = coreNameArray.constData(); - corePathData = corePathArray.constData(); - dbNameData = dbNameArray.constData(); - crc32Data = crc32Array.constData(); - - if (path_is_compressed_file(pathData)) - { - struct string_list *list = file_archive_get_file_list(pathData, NULL); - - if (list) - { - if (list->size == 1) - { - /* assume archives with one file should have that file loaded directly */ - pathArray = QDir::toNativeSeparators(QString(pathData) + "#" + list->elems[0].data).toUtf8(); - pathData = pathArray.constData(); - } - - string_list_free(list); - } - } - - playlist = playlist_init(playlistPathData, COLLECTION_SIZE); - - playlist_update(playlist, index, pathData, labelData, - corePathData, coreNameData, crc32Data, dbNameData); - playlist_write_file(playlist); - playlist_free(playlist); - - reloadPlaylists(); - - return true; -} - void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) { QScopedPointer menu; @@ -2202,273 +1240,6 @@ void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) } } -void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) -{ - settings_t *settings = config_get_ptr(); - QScopedPointer menu; - QScopedPointer associateMenu; - QScopedPointer hiddenPlaylistsMenu; - QScopedPointer hideAction; - QScopedPointer newPlaylistAction; - QScopedPointer deletePlaylistAction; - QPointer selectedAction; - QPoint cursorPos = QCursor::pos(); - QListWidgetItem *selectedItem = m_listWidget->itemAt(m_listWidget->viewport()->mapFromGlobal(cursorPos)); - QDir playlistDir(settings->paths.directory_playlist); - QString playlistDirAbsPath = playlistDir.absolutePath(); - QString currentPlaylistDirPath; - QString currentPlaylistPath; - QString currentPlaylistFileName; - QFile currentPlaylistFile; - QByteArray currentPlaylistFileNameArray; - QFileInfo currentPlaylistFileInfo; - QMap coreList; - core_info_list_t *core_info_list = NULL; - union string_list_elem_attr attr = {0}; - struct string_list *stnames = NULL; - struct string_list *stcores = NULL; - unsigned i = 0; - int j = 0; - size_t found = 0; - const char *currentPlaylistFileNameData = NULL; - char new_playlist_names[PATH_MAX_LENGTH]; - char new_playlist_cores[PATH_MAX_LENGTH]; - bool specialPlaylist = false; - bool foundHiddenPlaylist = false; - - new_playlist_names[0] = new_playlist_cores[0] = '\0'; - - stnames = string_split(settings->arrays.playlist_names, ";"); - stcores = string_split(settings->arrays.playlist_cores, ";"); - - if (selectedItem) - { - currentPlaylistPath = selectedItem->data(Qt::UserRole).toString(); - currentPlaylistFile.setFileName(currentPlaylistPath); - - currentPlaylistFileInfo = QFileInfo(currentPlaylistPath); - currentPlaylistFileName = currentPlaylistFileInfo.fileName(); - currentPlaylistDirPath = currentPlaylistFileInfo.absoluteDir().absolutePath(); - - currentPlaylistFileNameArray.append(currentPlaylistFileName); - currentPlaylistFileNameData = currentPlaylistFileNameArray.constData(); - } - - menu.reset(new QMenu(this)); - menu->setObjectName("menu"); - - hiddenPlaylistsMenu.reset(new QMenu(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS), this)); - newPlaylistAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST)) + "...", this)); - - hiddenPlaylistsMenu->setObjectName("hiddenPlaylistsMenu"); - - menu->addAction(newPlaylistAction.data()); - - if (currentPlaylistFile.exists()) - { - deletePlaylistAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST)) + "...", this)); - menu->addAction(deletePlaylistAction.data()); - } - - if (selectedItem) - { - hideAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_HIDE), this)); - menu->addAction(hideAction.data()); - } - - for (j = 0; j < m_listWidget->count(); j++) - { - QListWidgetItem *item = m_listWidget->item(j); - bool hidden = m_listWidget->isItemHidden(item); - - if (hidden) - { - QAction *action = hiddenPlaylistsMenu->addAction(item->text()); - action->setProperty("row", j); - action->setProperty("core_path", item->data(Qt::UserRole).toString()); - foundHiddenPlaylist = true; - } - } - - if (!foundHiddenPlaylist) - { - QAction *action = hiddenPlaylistsMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE)); - action->setProperty("row", -1); - } - - menu->addMenu(hiddenPlaylistsMenu.data()); - - if (currentPlaylistDirPath != playlistDirAbsPath) - { - /* special playlists like history etc. can't have an association */ - specialPlaylist = true; - } - - if (!specialPlaylist) - { - associateMenu.reset(new QMenu(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ASSOCIATE_CORE), this)); - associateMenu->setObjectName("associateMenu"); - - core_info_get_list(&core_info_list); - - for (i = 0; i < core_info_list->count && core_info_list->count > 0; i++) - { - const core_info_t *core = &core_info_list->list[i]; - coreList[core->core_name] = core; - } - - { - QMapIterator coreListIterator(coreList); - QVector > cores; - - while (coreListIterator.hasNext()) - { - QString key; - const core_info_t *core = NULL; - QString name; - QHash hash; - - coreListIterator.next(); - - key = coreListIterator.key(); - core = coreList.value(key); - - if (string_is_empty(core->core_name)) - name = core->display_name; - else - name = core->core_name; - - if (name.isEmpty()) - continue; - - hash["name"] = name; - hash["core_path"] = core->path; - - cores.append(hash); - } - - std::sort(cores.begin(), cores.end(), comp_hash_name_key_lower); - - for (j = 0; j < cores.count(); j++) - { - const QHash &hash = cores.at(j); - QAction *action = associateMenu->addAction(hash.value("name")); - - action->setProperty("core_path", hash.value("core_path")); - } - } - - menu->addMenu(associateMenu.data()); - } - - selectedAction = menu->exec(cursorPos); - - if (!selectedAction) - goto end; - - if (!specialPlaylist && selectedAction->parent() == associateMenu.data()) - { - found = string_list_find_elem(stnames, currentPlaylistFileNameData); - - if (found) - string_list_set(stcores, static_cast(found - 1), selectedAction->property("core_path").toString().toUtf8().constData()); - else - { - string_list_append(stnames, currentPlaylistFileNameData, attr); - string_list_append(stcores, "DETECT", attr); - - found = string_list_find_elem(stnames, currentPlaylistFileNameData); - - if (found) - string_list_set(stcores, static_cast(found - 1), selectedAction->property("core_path").toString().toUtf8().constData()); - } - - string_list_join_concat(new_playlist_names, - sizeof(new_playlist_names), stnames, ";"); - string_list_join_concat(new_playlist_cores, - sizeof(new_playlist_cores), stcores, ";"); - - strlcpy(settings->arrays.playlist_names, - new_playlist_names, sizeof(settings->arrays.playlist_names)); - strlcpy(settings->arrays.playlist_cores, - new_playlist_cores, sizeof(settings->arrays.playlist_cores)); - } - else if (selectedAction == deletePlaylistAction.data()) - { - if (currentPlaylistFile.exists()) - { - if (showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST)).arg(selectedItem->text()), MainWindow::MSGBOX_TYPE_QUESTION_YESNO, Qt::ApplicationModal, false)) - { - if (currentPlaylistFile.remove()) - reloadPlaylists(); - else - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - } - } - } - else if (selectedAction == newPlaylistAction.data()) - { - QString name = QInputDialog::getText(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST), msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME)); - QString newPlaylistPath = playlistDirAbsPath + "/" + name + file_path_str(FILE_PATH_LPL_EXTENSION); - QFile file(newPlaylistPath); - - if (file.open(QIODevice::WriteOnly)) - file.close(); - - reloadPlaylists(); - } - else if (selectedAction == hideAction.data()) - { - int row = m_listWidget->row(selectedItem); - - if (row >= 0) - { - QStringList hiddenPlaylists = m_settings->value("hidden_playlists").toStringList(); - - if (!hiddenPlaylists.contains(currentPlaylistFileName)) - { - hiddenPlaylists.append(currentPlaylistFileName); - m_settings->setValue("hidden_playlists", hiddenPlaylists); - } - - m_listWidget->setRowHidden(row, true); - } - } - else if (selectedAction->parent() == hiddenPlaylistsMenu.data()) - { - QVariant rowVariant = selectedAction->property("row"); - - if (rowVariant.isValid()) - { - QStringList hiddenPlaylists = m_settings->value("hidden_playlists").toStringList(); - int row = rowVariant.toInt(); - - if (row >= 0) - { - QString playlistPath = selectedAction->property("core_path").toString(); - QFileInfo playlistFileInfo(playlistPath); - QString playlistFileName = playlistFileInfo.fileName(); - - if (hiddenPlaylists.contains(playlistFileName)) - { - hiddenPlaylists.removeOne(playlistFileName); - m_settings->setValue("hidden_playlists", hiddenPlaylists); - } - - m_listWidget->setRowHidden(row, false); - } - } - } - - setCoreActions(); - -end: - if (stnames) - string_list_free(stnames); - if (stcores) - string_list_free(stcores); -} - void MainWindow::onFileBrowserTreeContextMenuRequested(const QPoint&) { #ifdef HAVE_LIBRETRODB @@ -2560,151 +1331,6 @@ void MainWindow::onGotReloadShaderParams() onShaderParamsClicked(); } -void MainWindow::deferReloadPlaylists() -{ - emit gotReloadPlaylists(); -} - -void MainWindow::onGotReloadPlaylists() -{ - reloadPlaylists(); -} - -void MainWindow::reloadPlaylists() -{ - QListWidgetItem *allPlaylistsItem = NULL; - QListWidgetItem *favoritesPlaylistsItem = NULL; - QListWidgetItem *imagePlaylistsItem = NULL; - QListWidgetItem *musicPlaylistsItem = NULL; - QListWidgetItem *videoPlaylistsItem = NULL; - QListWidgetItem *firstItem = NULL; - QListWidgetItem *currentItem = NULL; - settings_t *settings = config_get_ptr(); - QDir playlistDir(settings->paths.directory_playlist); - QString currentPlaylistPath; - QStringList hiddenPlaylists = m_settings->value("hidden_playlists").toStringList(); - int i = 0; - - currentItem = m_listWidget->currentItem(); - - if (currentItem) - { - currentPlaylistPath = currentItem->data(Qt::UserRole).toString(); - } - - getPlaylistFiles(); - - m_listWidget->clear(); - - allPlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS)); - allPlaylistsItem->setData(Qt::UserRole, ALL_PLAYLISTS_TOKEN); - - favoritesPlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES_TAB)); - favoritesPlaylistsItem->setData(Qt::UserRole, settings->paths.path_content_favorites); - - m_historyPlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_HISTORY_TAB)); - m_historyPlaylistsItem->setData(Qt::UserRole, settings->paths.path_content_history); - - imagePlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_IMAGES_TAB)); - imagePlaylistsItem->setData(Qt::UserRole, settings->paths.path_content_image_history); - - musicPlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MUSIC_TAB)); - musicPlaylistsItem->setData(Qt::UserRole, settings->paths.path_content_music_history); - - videoPlaylistsItem = new QListWidgetItem(m_folderIcon, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_TAB)); - videoPlaylistsItem->setData(Qt::UserRole, settings->paths.path_content_video_history); - - m_listWidget->addItem(allPlaylistsItem); - m_listWidget->addItem(favoritesPlaylistsItem); - m_listWidget->addItem(m_historyPlaylistsItem); - m_listWidget->addItem(imagePlaylistsItem); - m_listWidget->addItem(musicPlaylistsItem); - m_listWidget->addItem(videoPlaylistsItem); - - if (hiddenPlaylists.contains(ALL_PLAYLISTS_TOKEN)) - m_listWidget->setRowHidden(m_listWidget->row(allPlaylistsItem), true); - if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_favorites).fileName())) - m_listWidget->setRowHidden(m_listWidget->row(favoritesPlaylistsItem), true); - if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_history).fileName())) - m_listWidget->setRowHidden(m_listWidget->row(m_historyPlaylistsItem), true); - if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_image_history).fileName())) - m_listWidget->setRowHidden(m_listWidget->row(imagePlaylistsItem), true); - if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_music_history).fileName())) - m_listWidget->setRowHidden(m_listWidget->row(musicPlaylistsItem), true); - if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_video_history).fileName())) - m_listWidget->setRowHidden(m_listWidget->row(videoPlaylistsItem), true); - - for (i = 0; i < m_playlistFiles.count(); i++) - { - QListWidgetItem *item = NULL; - const QString &file = m_playlistFiles.at(i); - QString fileDisplayName = file; - QString fileName = file; - bool hasIcon = false; - QIcon icon; - QString iconPath; - - fileDisplayName.remove(file_path_str(FILE_PATH_LPL_EXTENSION)); - - iconPath = QString(settings->paths.directory_assets) + ICON_PATH + fileDisplayName + ".png"; - - hasIcon = QFile::exists(iconPath); - - if (hasIcon) - icon = QIcon(iconPath); - else - icon = m_folderIcon; - - item = new QListWidgetItem(icon, fileDisplayName); - item->setData(Qt::UserRole, playlistDir.absoluteFilePath(file)); - - m_listWidget->addItem(item); - - if (hiddenPlaylists.contains(fileName)) - { - int row = m_listWidget->row(item); - - if (row >= 0) - m_listWidget->setRowHidden(row, true); - } - } - - if (m_listWidget->count() > 0) - { - firstItem = m_listWidget->item(0); - - if (firstItem) - { - bool found = false; - - for (i = 0; i < m_listWidget->count(); i++) - { - QListWidgetItem *item = m_listWidget->item(i); - QString path; - - if (item) - { - path = item->data(Qt::UserRole).toString(); - - if (!currentPlaylistPath.isEmpty() && !path.isEmpty()) - { - if (path == currentPlaylistPath) - { - found = true; - m_listWidget->setCurrentItem(item); - break; - } - } - } - } - - /* the previous playlist must be gone now, just select the first one */ - if (!found) - m_listWidget->setCurrentItem(firstItem); - } - } -} - void MainWindow::appendLogMessage(const QString &msg) { emit gotLogMessage(msg); @@ -3207,20 +1833,6 @@ void MainWindow::onTableWidgetDeletePressed() deleteCurrentPlaylistItem(); } -QString MainWindow::getCurrentPlaylistPath() -{ - QListWidgetItem *playlistItem = m_listWidget->currentItem(); - QHash contentHash; - QString playlistPath; - - if (!playlistItem) - return playlistPath; - - playlistPath = playlistItem->data(Qt::UserRole).toString(); - - return playlistPath; -} - QHash MainWindow::getCurrentContentHash() { QTableWidgetItem *contentItem = m_tableWidget->currentItem(); @@ -3241,42 +1853,6 @@ QHash MainWindow::getCurrentContentHash() return contentHash; } -void MainWindow::deleteCurrentPlaylistItem() -{ - QString playlistPath = getCurrentPlaylistPath(); - QByteArray playlistArray; - QHash contentHash = getCurrentContentHash(); - playlist_t *playlist = NULL; - const char *playlistData = NULL; - unsigned index = 0; - bool ok = false; - - if (playlistPath.isEmpty()) - return; - - if (contentHash.isEmpty()) - return; - - playlistArray = playlistPath.toUtf8(); - playlistData = playlistArray.constData(); - - index = contentHash.value("index").toUInt(&ok); - - if (!ok) - return; - - if (!showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM)).arg(contentHash["label"]), MainWindow::MSGBOX_TYPE_QUESTION_YESNO, Qt::ApplicationModal, false)) - return; - - playlist = playlist_init(playlistData, COLLECTION_SIZE); - - playlist_delete_index(playlist, index); - playlist_write_file(playlist); - playlist_free(playlist); - - reloadPlaylists(); -} - void MainWindow::onContentItemDoubleClicked(QTableWidgetItem*) { onRunClicked(); @@ -3558,50 +2134,6 @@ ViewOptionsDialog* MainWindow::viewOptionsDialog() return m_viewOptionsDialog; } -QVector > MainWindow::getPlaylistDefaultCores() -{ - settings_t *settings = config_get_ptr(); - struct string_list *playlists = string_split(settings->arrays.playlist_names, ";"); - struct string_list *cores = string_split(settings->arrays.playlist_cores, ";"); - unsigned i = 0; - QVector > coreList; - - if (!playlists || !cores) - { - RARCH_WARN("[Qt]: Could not parse one of playlist_names or playlist_cores\n"); - goto finish; - } - else if (playlists->size != cores->size) - { - RARCH_WARN("[Qt]: playlist_names array size differs from playlist_cores\n"); - goto finish; - } - - if (playlists->size == 0) - goto finish; - - for (i = 0; i < playlists->size; i++) - { - const char *playlist = playlists->elems[i].data; - const char *core = cores->elems[i].data; - QHash hash; - - hash["playlist_filename"] = playlist; - hash["playlist_filename"].remove(file_path_str(FILE_PATH_LPL_EXTENSION)); - hash["core_path"] = core; - - coreList.append(hash); - } - -finish: - if (playlists) - string_list_free(playlists); - if (cores) - string_list_free(cores); - - return coreList; -} - void MainWindow::setCoreActions() { QTableWidgetItem *currentContentItem = m_tableWidget->currentItem(); @@ -3836,14 +2368,6 @@ QComboBox* MainWindow::launchWithComboBox() return m_launchWithComboBox; } -void MainWindow::getPlaylistFiles() -{ - settings_t *settings = config_get_ptr(); - QDir playlistDir(settings->paths.directory_playlist); - - m_playlistFiles = playlistDir.entryList(QDir::NoDotAndDotDot | QDir::Readable | QDir::Files, QDir::Name); -} - void MainWindow::onSearchLineEditEdited(const QString &text) { int i = 0; @@ -4545,140 +3069,6 @@ GridItem* MainWindow::doDeferredImageLoad(GridItem *item, QString path) return item; } -void MainWindow::addPlaylistItemsToGrid(const QStringList &paths, bool add) -{ - QVector > items; - int i; - - if (paths.isEmpty()) - return; - - for (i = 0; i < paths.size(); i++) - { - int j; - QVector > vec = getPlaylistItems(paths.at(i)); - /* QVector::append() wasn't added until 5.5, so just do it the old fashioned way */ - for (j = 0; j < vec.size(); j++) - { - if (add && m_allPlaylistsGridMaxCount > 0 && items.size() >= m_allPlaylistsGridMaxCount) - goto finish; - - items.append(vec.at(j)); - } - } -finish: - std::sort(items.begin(), items.end(), comp_hash_label_key_lower); - - addPlaylistHashToGrid(items); -} - -void MainWindow::addPlaylistHashToGrid(const QVector > &items) -{ - QScreen *screen = qApp->primaryScreen(); - QSize screenSize = screen->size(); - QListWidgetItem *currentItem = m_listWidget->currentItem(); - settings_t *settings = config_get_ptr(); - int i = 0; - int zoomValue = m_zoomSlider->value(); - - m_gridProgressBar->setMinimum(0); - m_gridProgressBar->setMaximum(qMax(0, items.count() - 1)); - m_gridProgressBar->setValue(0); - - for (i = 0; i < items.count(); i++) - { - const QHash &hash = items.at(i); - QPointer item; - QPointer label; - QString thumbnailFileNameNoExt; - QLabel *newLabel = NULL; - QSize thumbnailWidgetSizeHint(screenSize.width() / 8, screenSize.height() / 8); - QByteArray extension; - QString extensionStr; - QString imagePath; - int lastIndex = -1; - - if (m_listWidget->currentItem() != currentItem) - { - /* user changed the current playlist before we finished loading... abort */ - m_gridProgressWidget->hide(); - break; - } - - item = new GridItem(); - - lastIndex = hash["path"].lastIndexOf('.'); - - if (lastIndex >= 0) - { - extensionStr = hash["path"].mid(lastIndex + 1); - - if (!extensionStr.isEmpty()) - { - extension = extensionStr.toLower().toUtf8(); - } - } - - if (!extension.isEmpty() && m_imageFormats.contains(extension)) - { - /* use thumbnail widgets to show regular image files */ - imagePath = hash["path"]; - } - else - { - thumbnailFileNameNoExt = hash["label_noext"]; - thumbnailFileNameNoExt.replace(m_fileSanitizerRegex, "_"); - imagePath = QString(settings->paths.directory_thumbnails) + "/" + hash.value("db_name") + "/" + THUMBNAIL_BOXART + "/" + thumbnailFileNameNoExt + ".png"; - } - - item->hash = hash; - item->widget = new ThumbnailWidget(); - item->widget->setSizeHint(thumbnailWidgetSizeHint); - item->widget->setFixedSize(item->widget->sizeHint()); - item->widget->setLayout(new QVBoxLayout()); - item->widget->setObjectName("thumbnailWidget"); - item->widget->setProperty("hash", QVariant::fromValue >(hash)); - - connect(item->widget, SIGNAL(mouseDoubleClicked()), this, SLOT(onGridItemDoubleClicked())); - connect(item->widget, SIGNAL(mousePressed()), this, SLOT(onGridItemClicked())); - - label = new ThumbnailLabel(item->widget); - label->setObjectName("thumbnailGridLabel"); - - item->label = label; - item->labelText = hash.value("label"); - - newLabel = new QLabel(item->labelText, item->widget); - newLabel->setObjectName("thumbnailQLabel"); - newLabel->setAlignment(Qt::AlignCenter); - newLabel->setToolTip(item->labelText); - - calcGridItemSize(item, zoomValue); - - item->widget->layout()->addWidget(label); - - item->widget->layout()->addWidget(newLabel); - qobject_cast(item->widget->layout())->setStretchFactor(label, 1); - - m_gridLayout->addWidgetDeferred(item->widget); - m_gridItems.append(item); - - loadImageDeferred(item, imagePath); - - if (i % 25 == 0) - { - /* Needed to update progress dialog while doing a lot of stuff on the main thread. */ - qApp->processEvents(); - } - - m_gridProgressBar->setValue(i); - } - - /* If there's only one entry, a min/max/value of all zero would make an indeterminate progress bar that never ends... so just hide it when we are done. */ - if (m_gridProgressBar->value() == m_gridProgressBar->maximum()) - m_gridProgressWidget->hide(); -} - void MainWindow::initContentGridLayout() { QListWidgetItem *item = m_listWidget->currentItem(); @@ -4827,122 +3217,6 @@ void MainWindow::initContentTableWidget() onSearchEnterPressed(); } -QVector > MainWindow::getPlaylistItems(QString pathString) -{ - QByteArray pathArray; - QVector > items; - const char *pathData = NULL; - playlist_t *playlist = NULL; - unsigned playlistSize = 0; - unsigned i = 0; - - pathArray.append(pathString); - pathData = pathArray.constData(); - - playlist = playlist_init(pathData, COLLECTION_SIZE); - playlistSize = playlist_get_size(playlist); - - for (i = 0; i < playlistSize; i++) - { - const char *path = NULL; - const char *label = NULL; - const char *core_path = NULL; - const char *core_name = NULL; - const char *crc32 = NULL; - const char *db_name = NULL; - QHash hash; - - playlist_get_index(playlist, i, - &path, &label, &core_path, - &core_name, &crc32, &db_name); - - if (string_is_empty(path)) - continue; - else - hash["path"] = path; - - hash["index"] = QString::number(i); - - if (string_is_empty(label)) - { - hash["label"] = path; - hash["label_noext"] = path; - } - else - { - hash["label"] = label; - hash["label_noext"] = label; - } - - if (!string_is_empty(core_path)) - hash["core_path"] = core_path; - - if (!string_is_empty(core_name)) - hash["core_name"] = core_name; - - if (!string_is_empty(crc32)) - hash["crc32"] = crc32; - - if (!string_is_empty(db_name)) - { - hash["db_name"] = db_name; - hash["db_name"].remove(file_path_str(FILE_PATH_LPL_EXTENSION)); - } - - items.append(hash); - } - - playlist_free(playlist); - playlist = NULL; - - return items; -} - -void MainWindow::addPlaylistItemsToTable(const QStringList &paths, bool add) -{ - QVector > items; - int i; - - if (paths.isEmpty()) - return; - - for (i = 0; i < paths.size(); i++) - { - int j; - QVector > vec = getPlaylistItems(paths.at(i)); - /* QVector::append() wasn't added until 5.5, so just do it the old fashioned way */ - for (j = 0; j < vec.size(); j++) - { - if (add && m_allPlaylistsListMaxCount > 0 && items.size() >= m_allPlaylistsListMaxCount) - goto finish; - - items.append(vec.at(j)); - } - } -finish: - addPlaylistHashToTable(items); -} - -void MainWindow::addPlaylistHashToTable(const QVector > &items) -{ - int i = 0; - int oldRowCount = m_tableWidget->rowCount(); - - m_tableWidget->setRowCount(oldRowCount + items.count()); - - for (i = 0; i < items.count(); i++) - { - QTableWidgetItem *labelItem = NULL; - const QHash &hash = items.at(i); - - labelItem = new QTableWidgetItem(hash.value("label")); - labelItem->setData(Qt::UserRole, QVariant::fromValue >(hash)); - labelItem->setFlags(labelItem->flags() & ~Qt::ItemIsEditable); - - m_tableWidget->setItem(oldRowCount + i, 0, labelItem); - } -} - void MainWindow::keyPressEvent(QKeyEvent *event) { /* @@ -4994,22 +3268,6 @@ void MainWindow::closeEvent(QCloseEvent *event) QMainWindow::closeEvent(event); } -void MainWindow::setAllPlaylistsListMaxCount(int count) -{ - if (count < 1) - count = 0; - - m_allPlaylistsListMaxCount = count; -} - -void MainWindow::setAllPlaylistsGridMaxCount(int count) -{ - if (count < 1) - count = 0; - - m_allPlaylistsGridMaxCount = count; -} - void MainWindow::onContributorsClicked() { QScopedPointer dialog(new QDialog()); @@ -5077,56 +3335,6 @@ void MainWindow::showDocs() QDesktopServices::openUrl(QUrl(DOCS_URL)); } -void MainWindow::onUpdateNetworkError(QNetworkReply::NetworkError code) -{ - QNetworkReply *reply = m_updateReply.data(); - QByteArray errorStringArray; - const char *errorStringData = NULL; - - m_updateProgressDialog->cancel(); - - if (!reply) - return; - - errorStringArray = reply->errorString().toUtf8(); - errorStringData = errorStringArray.constData(); - - RARCH_ERR("[Qt]: Network error code %d received: %s\n", code, errorStringData); - - /* Deleting the reply here seems to cause a strange heap-use-after-free crash. */ - /* - reply->disconnect(); - reply->abort(); - reply->deleteLater(); - */ -} - -void MainWindow::onUpdateNetworkSslErrors(const QList &errors) -{ - QNetworkReply *reply = m_updateReply.data(); - int i; - - if (!reply) - return; - - for (i = 0; i < errors.count(); i++) - { - const QSslError &error = errors.at(i); - QString string = QString("Ignoring SSL error code ") + QString::number(error.error()) + ": " + error.errorString(); - QByteArray stringArray = string.toUtf8(); - const char *stringData = stringArray.constData(); - RARCH_ERR("[Qt]: %s\n", stringData); - } - - /* ignore all SSL errors for now, like self-signed, expired etc. */ - reply->ignoreSslErrors(); -} - -void MainWindow::onUpdateDownloadCanceled() -{ - m_updateProgressDialog->cancel(); -} - void MainWindow::onShowErrorMessage(QString msg) { showMessageBox(msg, MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); @@ -5137,275 +3345,6 @@ void MainWindow::onShowInfoMessage(QString msg) showMessageBox(msg, MainWindow::MSGBOX_TYPE_INFO, Qt::ApplicationModal, false); } -void MainWindow::onRetroArchUpdateDownloadFinished() -{ - QNetworkReply *reply = m_updateReply.data(); - QNetworkReply::NetworkError error; - int code; - - m_updateProgressDialog->cancel(); - - /* At least on Linux, the progress dialog will refuse to hide itself and will stay on screen in a corrupted way if we happen to show an error message in this function. processEvents() will sometimes fix it, other times not... seems random. */ - qApp->processEvents(); - - if (!reply) - return; - - error = reply->error(); - code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - - if (m_updateFile.isOpen()) - m_updateFile.close(); - - if (code != 200) - { - emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": HTTP Code " + QString::number(code)); - RARCH_ERR("[Qt]: RetroArch update failed with HTTP status code: %d\n", code); - reply->disconnect(); - reply->abort(); - reply->deleteLater(); - return; - } - - if (error == QNetworkReply::NoError) - { - int index = m_updateFile.fileName().lastIndexOf(PARTIAL_EXTENSION); - QString newFileName = m_updateFile.fileName().left(index); - QFile newFile(newFileName); - - /* rename() requires the old file to be deleted first if it exists */ - if (newFile.exists() && !newFile.remove()) - RARCH_ERR("[Qt]: RetroArch update finished, but old file could not be deleted.\n"); - else - { - if (m_updateFile.rename(newFileName)) - { - RARCH_LOG("[Qt]: RetroArch update finished downloading successfully.\n"); - emit extractArchiveDeferred(newFileName); - } - else - { - RARCH_ERR("[Qt]: RetroArch update finished, but temp file could not be renamed.\n"); - emit showErrorMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE)); - } - } - } - else - { - QByteArray errorArray = reply->errorString().toUtf8(); - const char *errorData = errorArray.constData(); - - RARCH_ERR("[Qt]: RetroArch update ended prematurely: %s\n", errorData); - emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": Code " + QString::number(code) + ": " + errorData); - } - - reply->disconnect(); - reply->close(); - reply->deleteLater(); -} - -static void extractCB(void *task_data, void *user_data, const char *err) -{ - decompress_task_data_t *dec = (decompress_task_data_t*)task_data; - MainWindow *mainwindow = (MainWindow*)user_data; - - if (err) - RARCH_ERR("%s", err); - - if (dec) - { - if (filestream_exists(dec->source_file)) - filestream_delete(dec->source_file); - - free(dec->source_file); - free(dec); - } - - mainwindow->onUpdateRetroArchFinished(string_is_empty(err)); -} - -void MainWindow::onUpdateRetroArchFinished(bool success) -{ - m_updateProgressDialog->cancel(); - - if (!success) - { - RARCH_ERR("[Qt]: RetroArch update failed.\n"); - emit showErrorMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED)); - return; - } - - RARCH_LOG("[Qt]: RetroArch update finished successfully.\n"); - - emit showInfoMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED)); -} - -int MainWindow::onExtractArchive(QString path) -{ - QByteArray pathArray = path.toUtf8(); - const char *file = pathArray.constData(); - file_archive_transfer_t state; - struct archive_extract_userdata userdata; - struct string_list *file_list = file_archive_get_file_list(file, NULL); - bool returnerr = true; - unsigned i; - - if (!file_list || file_list->size == 0) - { - showMessageBox("Error: Archive is empty.", MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - RARCH_ERR("[Qt]: Downloaded archive is empty?\n"); - return -1; - } - - for (i = 0; i < file_list->size; i++) - { - QFile fileObj(file_list->elems[i].data); - - if (fileObj.exists()) - { - if (!fileObj.remove()) - { - /* if we cannot delete the existing file to update it, rename it for now and delete later */ - QFile fileTemp(fileObj.fileName() + TEMP_EXTENSION); - - if (fileTemp.exists()) - { - if (!fileTemp.remove()) - { - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - RARCH_ERR("[Qt]: Could not delete file: %s\n", file_list->elems[i].data); - return -1; - } - } - - if (!fileObj.rename(fileTemp.fileName())) - { - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - RARCH_ERR("[Qt]: Could not rename file: %s\n", file_list->elems[i].data); - return -1; - } - } - } - } - - string_list_free(file_list); - - memset(&state, 0, sizeof(state)); - memset(&userdata, 0, sizeof(userdata)); - - state.type = ARCHIVE_TRANSFER_INIT; - - m_updateProgressDialog->setWindowModality(Qt::NonModal); - m_updateProgressDialog->setMinimumDuration(0); - m_updateProgressDialog->setRange(0, 0); - m_updateProgressDialog->setAutoClose(true); - m_updateProgressDialog->setAutoReset(true); - m_updateProgressDialog->setValue(0); - m_updateProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_EXTRACTING)) + "..."); - m_updateProgressDialog->setCancelButtonText(QString()); - m_updateProgressDialog->show(); - - if (!task_push_decompress(file, ".", - NULL, NULL, NULL, - extractCB, this)) - { - m_updateProgressDialog->cancel(); - return -1; - } - - return returnerr; -} - -void MainWindow::onUpdateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) -{ - QNetworkReply *reply = m_updateReply.data(); - int progress = (bytesReceived / (float)bytesTotal) * 100.0f; - - if (!reply) - return; - - m_updateProgressDialog->setValue(progress); -} - -void MainWindow::onUpdateDownloadReadyRead() -{ - QNetworkReply *reply = m_updateReply.data(); - - if (!reply) - return; - - m_updateFile.write(reply->readAll()); -} - -void MainWindow::updateRetroArchNightly() -{ - QUrl url(QUrl(buildbot_server_url).resolved(QUrl(RETROARCH_NIGHTLY_UPDATE_PATH))); - QNetworkRequest request(url); - QNetworkReply *reply = NULL; - QByteArray urlArray = url.toString().toUtf8(); - const char *urlData = urlArray.constData(); - - if (m_updateFile.isOpen()) - { - RARCH_ERR("[Qt]: File is already open.\n"); - return; - } - else - { - QString fileName = QFileInfo(url.toString()).fileName() + PARTIAL_EXTENSION; - QByteArray fileNameArray = fileName.toUtf8(); - const char *fileNameData = fileNameArray.constData(); - - m_updateFile.setFileName(fileName); - - if (!m_updateFile.open(QIODevice::WriteOnly)) - { - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - RARCH_ERR("[Qt]: Could not open file for writing: %s\n", fileNameData); - return; - } - } - - RARCH_LOG("[Qt]: Starting update of RetroArch...\n"); - RARCH_LOG("[Qt]: Downloading URL %s\n", urlData); - - request.setHeader(QNetworkRequest::UserAgentHeader, USER_AGENT); - - m_updateProgressDialog->setWindowModality(Qt::NonModal); - m_updateProgressDialog->setMinimumDuration(0); - m_updateProgressDialog->setRange(0, 100); - m_updateProgressDialog->setAutoClose(true); - m_updateProgressDialog->setAutoReset(true); - m_updateProgressDialog->setValue(0); - m_updateProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_DOWNLOADING)) + "..."); - m_updateProgressDialog->setCancelButtonText(tr("Cancel")); - m_updateProgressDialog->show(); - - m_updateReply = m_networkManager->get(request); - reply = m_updateReply.data(); - - /* make sure any previous connection is removed first */ - disconnect(m_updateProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); - disconnect(m_updateProgressDialog, SIGNAL(canceled()), m_updateProgressDialog, SLOT(cancel())); - connect(m_updateProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); - connect(m_updateProgressDialog, SIGNAL(canceled()), m_updateProgressDialog, SLOT(cancel())); - - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onUpdateNetworkError(QNetworkReply::NetworkError))); - connect(reply, SIGNAL(sslErrors(const QList&)), this, SLOT(onUpdateNetworkSslErrors(const QList&))); - connect(reply, SIGNAL(finished()), this, SLOT(onRetroArchUpdateDownloadFinished())); - connect(reply, SIGNAL(readyRead()), this, SLOT(onUpdateDownloadReadyRead())); - connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onUpdateDownloadProgress(qint64, qint64))); - -} - -const QPixmap getInvader() -{ - QPixmap pix; - pix.loadFromData(invader_png, invader_png_len, "PNG"); - - return pix; -} - static void* ui_window_qt_init(void) { ui_window.qtWindow = new MainWindow(); diff --git a/ui/drivers/qt/updateretroarch.cpp b/ui/drivers/qt/updateretroarch.cpp new file mode 100644 index 0000000000..da67edb862 --- /dev/null +++ b/ui/drivers/qt/updateretroarch.cpp @@ -0,0 +1,355 @@ +#include +#include +#include + +#include "../ui_qt.h" + +extern "C" { +#include +#include +#include +#include "../../../tasks/tasks_internal.h" +#include "../../../verbosity.h" +#include "../../../config.def.h" +} + +#define USER_AGENT "RetroArch-WIMP/1.0" +#define PARTIAL_EXTENSION ".partial" +#define TEMP_EXTENSION ".update_tmp" +#define RETROARCH_NIGHTLY_UPDATE_PATH "../RetroArch_update.zip" + +static void extractCB(void *task_data, void *user_data, const char *err) +{ + decompress_task_data_t *dec = (decompress_task_data_t*)task_data; + MainWindow *mainwindow = (MainWindow*)user_data; + + if (err) + RARCH_ERR("%s", err); + + if (dec) + { + if (filestream_exists(dec->source_file)) + filestream_delete(dec->source_file); + + free(dec->source_file); + free(dec); + } + + mainwindow->onUpdateRetroArchFinished(string_is_empty(err)); +} + +void MainWindow::removeUpdateTempFiles() +{ + /* a QDir with no path means the current working directory */ + QDir dir; + QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name); + int i; + + for (i = 0; i < dirList.count(); i++) + { + QString path(dir.path() + "/" + dirList.at(i)); + QFile file(path); + + if (path.endsWith(TEMP_EXTENSION)) + { + QByteArray pathArray = path.toUtf8(); + const char *pathData = pathArray.constData(); + + if (file.remove()) + RARCH_LOG("[Qt]: removed temporary update file %s\n", pathData); + else + RARCH_LOG("[Qt]: could not remove temporary update file %s\n", pathData); + } + } +} + +void MainWindow::onUpdateNetworkError(QNetworkReply::NetworkError code) +{ + QNetworkReply *reply = m_updateReply.data(); + QByteArray errorStringArray; + const char *errorStringData = NULL; + + m_updateProgressDialog->cancel(); + + if (!reply) + return; + + errorStringArray = reply->errorString().toUtf8(); + errorStringData = errorStringArray.constData(); + + RARCH_ERR("[Qt]: Network error code %d received: %s\n", code, errorStringData); + + /* Deleting the reply here seems to cause a strange heap-use-after-free crash. */ + /* + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + */ +} + +void MainWindow::onUpdateNetworkSslErrors(const QList &errors) +{ + QNetworkReply *reply = m_updateReply.data(); + int i; + + if (!reply) + return; + + for (i = 0; i < errors.count(); i++) + { + const QSslError &error = errors.at(i); + QString string = QString("Ignoring SSL error code ") + QString::number(error.error()) + ": " + error.errorString(); + QByteArray stringArray = string.toUtf8(); + const char *stringData = stringArray.constData(); + RARCH_ERR("[Qt]: %s\n", stringData); + } + + /* ignore all SSL errors for now, like self-signed, expired etc. */ + reply->ignoreSslErrors(); +} + +void MainWindow::onUpdateDownloadCanceled() +{ + m_updateProgressDialog->cancel(); +} + +void MainWindow::onRetroArchUpdateDownloadFinished() +{ + QNetworkReply *reply = m_updateReply.data(); + QNetworkReply::NetworkError error; + int code; + + m_updateProgressDialog->cancel(); + + /* At least on Linux, the progress dialog will refuse to hide itself and will stay on screen in a corrupted way if we happen to show an error message in this function. processEvents() will sometimes fix it, other times not... seems random. */ + qApp->processEvents(); + + if (!reply) + return; + + error = reply->error(); + code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (m_updateFile.isOpen()) + m_updateFile.close(); + + if (code != 200) + { + emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": HTTP Code " + QString::number(code)); + RARCH_ERR("[Qt]: RetroArch update failed with HTTP status code: %d\n", code); + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + return; + } + + if (error == QNetworkReply::NoError) + { + int index = m_updateFile.fileName().lastIndexOf(PARTIAL_EXTENSION); + QString newFileName = m_updateFile.fileName().left(index); + QFile newFile(newFileName); + + /* rename() requires the old file to be deleted first if it exists */ + if (newFile.exists() && !newFile.remove()) + RARCH_ERR("[Qt]: RetroArch update finished, but old file could not be deleted.\n"); + else + { + if (m_updateFile.rename(newFileName)) + { + RARCH_LOG("[Qt]: RetroArch update finished downloading successfully.\n"); + emit extractArchiveDeferred(newFileName); + } + else + { + RARCH_ERR("[Qt]: RetroArch update finished, but temp file could not be renamed.\n"); + emit showErrorMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE)); + } + } + } + else + { + QByteArray errorArray = reply->errorString().toUtf8(); + const char *errorData = errorArray.constData(); + + RARCH_ERR("[Qt]: RetroArch update ended prematurely: %s\n", errorData); + emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": Code " + QString::number(code) + ": " + errorData); + } + + reply->disconnect(); + reply->close(); + reply->deleteLater(); +} + +void MainWindow::onUpdateRetroArchFinished(bool success) +{ + m_updateProgressDialog->cancel(); + + if (!success) + { + RARCH_ERR("[Qt]: RetroArch update failed.\n"); + emit showErrorMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED)); + return; + } + + RARCH_LOG("[Qt]: RetroArch update finished successfully.\n"); + + emit showInfoMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED)); +} + +int MainWindow::onExtractArchive(QString path) +{ + QByteArray pathArray = path.toUtf8(); + const char *file = pathArray.constData(); + file_archive_transfer_t state; + struct archive_extract_userdata userdata; + struct string_list *file_list = file_archive_get_file_list(file, NULL); + bool returnerr = true; + unsigned i; + + if (!file_list || file_list->size == 0) + { + showMessageBox("Error: Archive is empty.", MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Downloaded archive is empty?\n"); + return -1; + } + + for (i = 0; i < file_list->size; i++) + { + QFile fileObj(file_list->elems[i].data); + + if (fileObj.exists()) + { + if (!fileObj.remove()) + { + /* if we cannot delete the existing file to update it, rename it for now and delete later */ + QFile fileTemp(fileObj.fileName() + TEMP_EXTENSION); + + if (fileTemp.exists()) + { + if (!fileTemp.remove()) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Could not delete file: %s\n", file_list->elems[i].data); + return -1; + } + } + + if (!fileObj.rename(fileTemp.fileName())) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Could not rename file: %s\n", file_list->elems[i].data); + return -1; + } + } + } + } + + string_list_free(file_list); + + memset(&state, 0, sizeof(state)); + memset(&userdata, 0, sizeof(userdata)); + + state.type = ARCHIVE_TRANSFER_INIT; + + m_updateProgressDialog->setWindowModality(Qt::NonModal); + m_updateProgressDialog->setMinimumDuration(0); + m_updateProgressDialog->setRange(0, 0); + m_updateProgressDialog->setAutoClose(true); + m_updateProgressDialog->setAutoReset(true); + m_updateProgressDialog->setValue(0); + m_updateProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_EXTRACTING)) + "..."); + m_updateProgressDialog->setCancelButtonText(QString()); + m_updateProgressDialog->show(); + + if (!task_push_decompress(file, ".", + NULL, NULL, NULL, + extractCB, this)) + { + m_updateProgressDialog->cancel(); + return -1; + } + + return returnerr; +} + +void MainWindow::onUpdateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + QNetworkReply *reply = m_updateReply.data(); + int progress = (bytesReceived / (float)bytesTotal) * 100.0f; + + if (!reply) + return; + + m_updateProgressDialog->setValue(progress); +} + +void MainWindow::onUpdateDownloadReadyRead() +{ + QNetworkReply *reply = m_updateReply.data(); + + if (!reply) + return; + + m_updateFile.write(reply->readAll()); +} + +void MainWindow::updateRetroArchNightly() +{ + QUrl url(QUrl(buildbot_server_url).resolved(QUrl(RETROARCH_NIGHTLY_UPDATE_PATH))); + QNetworkRequest request(url); + QNetworkReply *reply = NULL; + QByteArray urlArray = url.toString().toUtf8(); + const char *urlData = urlArray.constData(); + + if (m_updateFile.isOpen()) + { + RARCH_ERR("[Qt]: File is already open.\n"); + return; + } + else + { + QString fileName = QFileInfo(url.toString()).fileName() + PARTIAL_EXTENSION; + QByteArray fileNameArray = fileName.toUtf8(); + const char *fileNameData = fileNameArray.constData(); + + m_updateFile.setFileName(fileName); + + if (!m_updateFile.open(QIODevice::WriteOnly)) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Could not open file for writing: %s\n", fileNameData); + return; + } + } + + RARCH_LOG("[Qt]: Starting update of RetroArch...\n"); + RARCH_LOG("[Qt]: Downloading URL %s\n", urlData); + + request.setHeader(QNetworkRequest::UserAgentHeader, USER_AGENT); + + m_updateProgressDialog->setWindowModality(Qt::NonModal); + m_updateProgressDialog->setMinimumDuration(0); + m_updateProgressDialog->setRange(0, 100); + m_updateProgressDialog->setAutoClose(true); + m_updateProgressDialog->setAutoReset(true); + m_updateProgressDialog->setValue(0); + m_updateProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_DOWNLOADING)) + "..."); + m_updateProgressDialog->setCancelButtonText(tr("Cancel")); + m_updateProgressDialog->show(); + + m_updateReply = m_networkManager->get(request); + reply = m_updateReply.data(); + + /* make sure any previous connection is removed first */ + disconnect(m_updateProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); + disconnect(m_updateProgressDialog, SIGNAL(canceled()), m_updateProgressDialog, SLOT(cancel())); + connect(m_updateProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); + connect(m_updateProgressDialog, SIGNAL(canceled()), m_updateProgressDialog, SLOT(cancel())); + + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onUpdateNetworkError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(sslErrors(const QList&)), this, SLOT(onUpdateNetworkSslErrors(const QList&))); + connect(reply, SIGNAL(finished()), this, SLOT(onRetroArchUpdateDownloadFinished())); + connect(reply, SIGNAL(readyRead()), this, SLOT(onUpdateDownloadReadyRead())); + connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onUpdateDownloadProgress(qint64, qint64))); + +} diff --git a/ui/drivers/qt/viewoptionsdialog.cpp b/ui/drivers/qt/viewoptionsdialog.cpp new file mode 100644 index 0000000000..a293b01a00 --- /dev/null +++ b/ui/drivers/qt/viewoptionsdialog.cpp @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "viewoptionsdialog.h" +#include "../ui_qt.h" + +extern "C" { +#include "../../../msg_hash.h" +} + +ViewOptionsDialog::ViewOptionsDialog(MainWindow *mainwindow, QWidget *parent) : + QDialog(parent) + ,m_mainwindow(mainwindow) + ,m_settings(mainwindow->settings()) + ,m_saveGeometryCheckBox(new QCheckBox(this)) + ,m_saveDockPositionsCheckBox(new QCheckBox(this)) + ,m_saveLastTabCheckBox(new QCheckBox(this)) + ,m_showHiddenFilesCheckBox(new QCheckBox(this)) + ,m_themeComboBox(new QComboBox(this)) + ,m_highlightColorPushButton(new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CHOOSE), this)) + ,m_highlightColor() + ,m_highlightColorLabel(new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR), this)) + ,m_customThemePath() + ,m_suggestLoadedCoreFirstCheckBox(new QCheckBox(this)) + ,m_allPlaylistsListMaxCountSpinBox(new QSpinBox(this)) + ,m_allPlaylistsGridMaxCountSpinBox(new QSpinBox(this)) +{ + QFormLayout *form = new QFormLayout(); + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE)); + + m_themeComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT), MainWindow::THEME_SYSTEM_DEFAULT); + m_themeComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK), MainWindow::THEME_DARK); + m_themeComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM), MainWindow::THEME_CUSTOM); + + m_allPlaylistsListMaxCountSpinBox->setRange(0, 99999); + m_allPlaylistsGridMaxCountSpinBox->setRange(0, 99999); + + form->setFormAlignment(Qt::AlignCenter); + form->setLabelAlignment(Qt::AlignCenter); + + setLayout(new QVBoxLayout(this)); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + connect(this, SIGNAL(accepted()), this, SLOT(onAccepted())); + connect(this, SIGNAL(rejected()), this, SLOT(onRejected())); + + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY), m_saveGeometryCheckBox); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS), m_saveDockPositionsCheckBox); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB), m_saveLastTabCheckBox); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES), m_showHiddenFilesCheckBox); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST), m_suggestLoadedCoreFirstCheckBox); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT), m_allPlaylistsListMaxCountSpinBox); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT), m_allPlaylistsGridMaxCountSpinBox); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME), m_themeComboBox); + form->addRow(m_highlightColorLabel, m_highlightColorPushButton); + + qobject_cast(layout())->addLayout(form); + layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); + layout()->addWidget(buttonBox); + + loadViewOptions(); + + connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onThemeComboBoxIndexChanged(int))); + connect(m_highlightColorPushButton, SIGNAL(clicked()), this, SLOT(onHighlightColorChoose())); +} + +void ViewOptionsDialog::onThemeComboBoxIndexChanged(int) +{ + MainWindow::Theme theme = static_cast(m_themeComboBox->currentData(Qt::UserRole).toInt()); + + if (theme == MainWindow::THEME_CUSTOM) + { + QString filePath = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_THEME)); + + if (filePath.isEmpty()) + { + int oldThemeIndex = m_themeComboBox->findData(m_mainwindow->getThemeFromString(m_settings->value("theme", "default").toString())); + + if (m_themeComboBox->count() > oldThemeIndex) + { + disconnect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onThemeComboBoxIndexChanged(int))); + m_themeComboBox->setCurrentIndex(oldThemeIndex); + connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onThemeComboBoxIndexChanged(int))); + } + } + else + { + m_customThemePath = filePath; + + if (m_mainwindow->setCustomThemeFile(filePath)) + m_mainwindow->setTheme(theme); + } + } + else + m_mainwindow->setTheme(theme); + + showOrHideHighlightColor(); +} + +void ViewOptionsDialog::onHighlightColorChoose() +{ + QPixmap highlightPixmap(m_highlightColorPushButton->iconSize()); + QColor currentHighlightColor = m_settings->value("highlight_color", QApplication::palette().highlight().color()).value(); + QColor newHighlightColor = QColorDialog::getColor(currentHighlightColor, this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_COLOR)); + + if (newHighlightColor.isValid()) + { + MainWindow::Theme theme = static_cast(m_themeComboBox->currentData(Qt::UserRole).toInt()); + + m_highlightColor = newHighlightColor; + m_settings->setValue("highlight_color", m_highlightColor); + highlightPixmap.fill(m_highlightColor); + m_highlightColorPushButton->setIcon(highlightPixmap); + m_mainwindow->setTheme(theme); + } +} + +void ViewOptionsDialog::loadViewOptions() +{ + QColor highlightColor = m_settings->value("highlight_color", QApplication::palette().highlight().color()).value(); + QPixmap highlightPixmap(m_highlightColorPushButton->iconSize()); + int themeIndex = 0; + + m_saveGeometryCheckBox->setChecked(m_settings->value("save_geometry", false).toBool()); + m_saveDockPositionsCheckBox->setChecked(m_settings->value("save_dock_positions", false).toBool()); + m_saveLastTabCheckBox->setChecked(m_settings->value("save_last_tab", false).toBool()); + m_showHiddenFilesCheckBox->setChecked(m_settings->value("show_hidden_files", true).toBool()); + m_suggestLoadedCoreFirstCheckBox->setChecked(m_settings->value("suggest_loaded_core_first", false).toBool()); + m_allPlaylistsListMaxCountSpinBox->setValue(m_settings->value("all_playlists_list_max_count", 0).toInt()); + m_allPlaylistsGridMaxCountSpinBox->setValue(m_settings->value("all_playlists_grid_max_count", 5000).toInt()); + + themeIndex = m_themeComboBox->findData(m_mainwindow->getThemeFromString(m_settings->value("theme", "default").toString())); + + if (m_themeComboBox->count() > themeIndex) + m_themeComboBox->setCurrentIndex(themeIndex); + + if (highlightColor.isValid()) + { + m_highlightColor = highlightColor; + highlightPixmap.fill(m_highlightColor); + m_highlightColorPushButton->setIcon(highlightPixmap); + } + + showOrHideHighlightColor(); +} + +void ViewOptionsDialog::showOrHideHighlightColor() +{ + if (m_mainwindow->theme() == MainWindow::THEME_DARK) + { + m_highlightColorLabel->show(); + m_highlightColorPushButton->show(); + } + else + { + m_highlightColorLabel->hide(); + m_highlightColorPushButton->hide(); + } +} + +void ViewOptionsDialog::saveViewOptions() +{ + m_settings->setValue("save_geometry", m_saveGeometryCheckBox->isChecked()); + m_settings->setValue("save_dock_positions", m_saveDockPositionsCheckBox->isChecked()); + m_settings->setValue("save_last_tab", m_saveLastTabCheckBox->isChecked()); + m_settings->setValue("theme", m_mainwindow->getThemeString(static_cast(m_themeComboBox->currentData(Qt::UserRole).toInt()))); + m_settings->setValue("show_hidden_files", m_showHiddenFilesCheckBox->isChecked()); + m_settings->setValue("highlight_color", m_highlightColor); + m_settings->setValue("suggest_loaded_core_first", m_suggestLoadedCoreFirstCheckBox->isChecked()); + m_settings->setValue("all_playlists_list_max_count", m_allPlaylistsListMaxCountSpinBox->value()); + m_settings->setValue("all_playlists_grid_max_count", m_allPlaylistsGridMaxCountSpinBox->value()); + + if (!m_mainwindow->customThemeString().isEmpty()) + m_settings->setValue("custom_theme", m_customThemePath); + + m_mainwindow->setAllPlaylistsListMaxCount(m_allPlaylistsListMaxCountSpinBox->value()); + m_mainwindow->setAllPlaylistsGridMaxCount(m_allPlaylistsGridMaxCountSpinBox->value()); +} + +void ViewOptionsDialog::onAccepted() +{ + MainWindow::Theme newTheme = static_cast(m_themeComboBox->currentData(Qt::UserRole).toInt()); + + m_mainwindow->setTheme(newTheme); + + saveViewOptions(); +} + +void ViewOptionsDialog::onRejected() +{ + loadViewOptions(); +} + +void ViewOptionsDialog::showDialog() +{ + loadViewOptions(); + show(); +} + +void ViewOptionsDialog::hideDialog() +{ + reject(); +} + diff --git a/ui/drivers/qt/viewoptionsdialog.h b/ui/drivers/qt/viewoptionsdialog.h new file mode 100644 index 0000000000..7b5c7c71fe --- /dev/null +++ b/ui/drivers/qt/viewoptionsdialog.h @@ -0,0 +1,49 @@ +#ifndef VIEWOPTIONSDIALOG_H +#define VIEWOPTIONSDIALOG_H + +#include + +class MainWindow; +class QSettings; +class QCheckBox; +class QComboBox; +class QPushButton; +class QColor; +class QLabel; +class QSpinBox; + +class ViewOptionsDialog : public QDialog +{ + Q_OBJECT +public: + ViewOptionsDialog(MainWindow *mainwindow, QWidget *parent = 0); +public slots: + void showDialog(); + void hideDialog(); + void onAccepted(); + void onRejected(); +private slots: + void onThemeComboBoxIndexChanged(int index); + void onHighlightColorChoose(); +private: + void loadViewOptions(); + void saveViewOptions(); + void showOrHideHighlightColor(); + + MainWindow *m_mainwindow; + QSettings *m_settings; + QCheckBox *m_saveGeometryCheckBox; + QCheckBox *m_saveDockPositionsCheckBox; + QCheckBox *m_saveLastTabCheckBox; + QCheckBox *m_showHiddenFilesCheckBox; + QComboBox *m_themeComboBox; + QPushButton *m_highlightColorPushButton; + QColor m_highlightColor; + QLabel *m_highlightColorLabel; + QString m_customThemePath; + QCheckBox *m_suggestLoadedCoreFirstCheckBox; + QSpinBox *m_allPlaylistsListMaxCountSpinBox; + QSpinBox *m_allPlaylistsGridMaxCountSpinBox; +}; + +#endif diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index 00c9d466fa..3909cb9209 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -16,6 +16,7 @@ extern "C" { #include +#include #ifdef HAVE_CONFIG_H #include "../../config.h" @@ -31,6 +32,8 @@ extern "C" { } #include "ui_qt.h" +#include "qt/filedropwidget.h" +#include "qt/viewoptionsdialog.h" #include #include diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index f1a1bd03b6..05972d13e2 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -45,6 +45,10 @@ extern "C" { #include "../../gfx/video_driver.h" } +#define ALL_PLAYLISTS_TOKEN "|||ALL|||" +#define ICON_PATH "/xmb/dot-art/png/" +#define THUMBNAIL_BOXART "Named_Boxarts" + class QApplication; class QCloseEvent; class QKeyEvent; @@ -78,6 +82,10 @@ class MainWindow; class ThumbnailWidget; class ThumbnailLabel; class FlowLayout; +class ShaderParamsDialog; +class CoreInfoDialog; +class PlaylistEntryDialog; +class ViewOptionsDialog; class GridItem : public QObject { @@ -147,21 +155,6 @@ protected slots: void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); }; -class FileDropWidget : public QWidget -{ - Q_OBJECT -public: - FileDropWidget(QWidget *parent = 0); -signals: - void filesDropped(QStringList files); - void deletePressed(); -protected: - void dragEnterEvent(QDragEnterEvent *event); - void dropEvent(QDropEvent *event); - void keyPressEvent(QKeyEvent *event); - void paintEvent(QPaintEvent *event); -}; - class TableWidget : public QTableWidget { Q_OBJECT @@ -188,82 +181,6 @@ private slots: void onLastWindowClosed(); }; -class PlaylistEntryDialog : public QDialog -{ - Q_OBJECT -public: - PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent = 0); - const QHash getSelectedCore(); - const QString getSelectedDatabase(); - const QString getSelectedName(); - const QString getSelectedPath(); - void setEntryValues(const QHash &contentHash); -public slots: - bool showDialog(const QHash &hash = QHash()); - void hideDialog(); - void onAccepted(); - void onRejected(); -private slots: - void onPathClicked(); -private: - void loadPlaylistOptions(); - - MainWindow *m_mainwindow; - QSettings *m_settings; - QLineEdit *m_nameLineEdit; - QLineEdit *m_pathLineEdit; - QComboBox *m_coreComboBox; - QComboBox *m_databaseComboBox; -}; - -class ViewOptionsDialog : public QDialog -{ - Q_OBJECT -public: - ViewOptionsDialog(MainWindow *mainwindow, QWidget *parent = 0); -public slots: - void showDialog(); - void hideDialog(); - void onAccepted(); - void onRejected(); -private slots: - void onThemeComboBoxIndexChanged(int index); - void onHighlightColorChoose(); -private: - void loadViewOptions(); - void saveViewOptions(); - void showOrHideHighlightColor(); - - MainWindow *m_mainwindow; - QSettings *m_settings; - QCheckBox *m_saveGeometryCheckBox; - QCheckBox *m_saveDockPositionsCheckBox; - QCheckBox *m_saveLastTabCheckBox; - QCheckBox *m_showHiddenFilesCheckBox; - QComboBox *m_themeComboBox; - QPushButton *m_highlightColorPushButton; - QColor m_highlightColor; - QLabel *m_highlightColorLabel; - QString m_customThemePath; - QCheckBox *m_suggestLoadedCoreFirstCheckBox; - QSpinBox *m_allPlaylistsListMaxCountSpinBox; - QSpinBox *m_allPlaylistsGridMaxCountSpinBox; -}; - -class ShaderParamsDialog : public QDialog -{ - Q_OBJECT -public: - ShaderParamsDialog(QWidget *parent = 0); - ~ShaderParamsDialog(); -signals: - void closed(); - void resized(QSize size); -protected: - void closeEvent(QCloseEvent *event); - void resizeEvent(QResizeEvent *event); -}; - class CoreInfoLabel : public QLabel { Q_OBJECT @@ -271,18 +188,6 @@ public: CoreInfoLabel(QString text = QString(), QWidget *parent = 0); }; -class CoreInfoDialog : public QDialog -{ - Q_OBJECT -public: - CoreInfoDialog(MainWindow *mainwindow, QWidget *parent = 0); -public slots: - void showCoreInfo(); -private: - QFormLayout *m_formLayout; - MainWindow *m_mainwindow; -}; - class CoreInfoWidget : public QWidget { Q_OBJECT From 1966b048327d739c4cf0348a73c50e967acf6c87 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 16 Aug 2018 22:58:35 -0400 Subject: [PATCH 057/182] Qt: windows buildfix --- ui/drivers/qt/playlist.cpp | 41 ++++++++++++++++++++++++++++ ui/drivers/qt/ui_qt_window.cpp | 49 +++------------------------------- ui/drivers/ui_qt.h | 1 + 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp index a3c81c3502..fbb6989da1 100644 --- a/ui/drivers/qt/playlist.cpp +++ b/ui/drivers/qt/playlist.cpp @@ -37,6 +37,20 @@ inline static bool comp_hash_label_key_lower(const QHash &lhs, return lhs.value("label").toLower() < rhs.value("label").toLower(); } +/* https://stackoverflow.com/questions/7246622/how-to-create-a-slider-with-a-non-linear-scale */ +static double expScale(double inputValue, double midValue, double maxValue) +{ + double returnValue = 0; + double M = maxValue / midValue; + double C = log(pow(M - 1, 2)); + double B = maxValue / (exp(C) - 1); + double A = -1 * B; + + returnValue = A + B * exp(C * inputValue); + + return returnValue; +} + static void addDirectoryFilesToList(QStringList &list, QDir &dir) { QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name); @@ -908,6 +922,33 @@ finish: addPlaylistHashToGrid(items); } +/* https://gist.github.com/andrey-str/0f9c7709cbf0c9c49ef9 */ +static void setElidedText(QLabel *label, QWidget *clipWidget, int padding, const QString &text) +{ + QFontMetrics metrix(label->font()); + int width = clipWidget->width() - padding; + QString clippedText = metrix.elidedText(text, Qt::ElideRight, width); + label->setText(clippedText); +} + +inline void MainWindow::calcGridItemSize(GridItem *item, int zoomValue) +{ + int newSize = 0; + QLabel *label = NULL; + + if (zoomValue < 50) + newSize = expScale(lerp(0, 49, 25, 49, zoomValue) / 50.0, 102, 256); + else + newSize = expScale(zoomValue / 100.0, 256, 1024); + + item->widget->setFixedSize(QSize(newSize, newSize)); + + label = item->widget->findChild("thumbnailQLabel"); + + if (label) + setElidedText(label, item->widget, item->widget->layout()->contentsMargins().left() + item->widget->layout()->spacing() + 2, item->labelText); +} + void MainWindow::addPlaylistHashToGrid(const QVector > &items) { QScreen *screen = qApp->primaryScreen(); diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 44583f313a..460e7542ad 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -113,24 +113,6 @@ static const QPixmap getInvader() return pix; } -static double lerp(double x, double y, double a, double b, double d) { - return a + (b - a) * ((double)(d - x) / (double)(y - x)); -} - -/* https://stackoverflow.com/questions/7246622/how-to-create-a-slider-with-a-non-linear-scale */ -static double expScale(double inputValue, double midValue, double maxValue) -{ - double returnValue = 0; - double M = maxValue / midValue; - double C = log(pow(M - 1, 2)); - double B = maxValue / (exp(C) - 1); - double A = -1 * B; - - returnValue = A + B * exp(C * inputValue); - - return returnValue; -} - #ifdef HAVE_LIBRETRODB static void scan_finished_handler(void *task_data, void *user_data, const char *err) { @@ -156,15 +138,6 @@ static void scan_finished_handler(void *task_data, void *user_data, const char * } #endif -/* https://gist.github.com/andrey-str/0f9c7709cbf0c9c49ef9 */ -static void setElidedText(QLabel *label, QWidget *clipWidget, int padding, const QString &text) -{ - QFontMetrics metrix(label->font()); - int width = clipWidget->width() - padding; - QString clippedText = metrix.elidedText(text, Qt::ElideRight, width); - label->setText(clippedText); -} - GridItem::GridItem() : QObject() ,widget(NULL) @@ -586,6 +559,10 @@ MainWindow::~MainWindow() removeGridItems(); } +double MainWindow::lerp(double x, double y, double a, double b, double d) { + return a + (b - a) * ((double)(d - x) / (double)(y - x)); +} + void MainWindow::onShaderParamsDialogResized(QSize size) { QVariant scrollAreaVariant = m_shaderParamsDialog->property("scrollArea"); @@ -949,24 +926,6 @@ void MainWindow::onListViewClicked() onCurrentListItemChanged(m_listWidget->currentItem(), NULL); } -inline void MainWindow::calcGridItemSize(GridItem *item, int zoomValue) -{ - int newSize = 0; - QLabel *label = NULL; - - if (zoomValue < 50) - newSize = expScale(lerp(0, 49, 25, 49, zoomValue) / 50.0, 102, 256); - else - newSize = expScale(zoomValue / 100.0, 256, 1024); - - item->widget->setFixedSize(QSize(newSize, newSize)); - - label = item->widget->findChild("thumbnailQLabel"); - - if (label) - setElidedText(label, item->widget, item->widget->layout()->contentsMargins().left() + item->widget->layout()->spacing() + 2, item->labelText); -} - void MainWindow::onZoomValueChanged(int value) { int i; diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 05972d13e2..418e1fb441 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -276,6 +276,7 @@ public: void addFilesToPlaylist(QStringList files); QString getCurrentPlaylistPath(); QHash getCurrentContentHash(); + static double lerp(double x, double y, double a, double b, double d); signals: void thumbnailChanged(const QPixmap &pixmap); From f130b261f458dc591d384681543c4e30fd515954 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 16 Aug 2018 23:14:52 -0400 Subject: [PATCH 058/182] Qt: Linux buildfix --- ui/drivers/qt/playlist.cpp | 40 ---------------------------------- ui/drivers/qt/ui_qt_window.cpp | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp index fbb6989da1..2f9271a0bf 100644 --- a/ui/drivers/qt/playlist.cpp +++ b/ui/drivers/qt/playlist.cpp @@ -38,19 +38,6 @@ inline static bool comp_hash_label_key_lower(const QHash &lhs, } /* https://stackoverflow.com/questions/7246622/how-to-create-a-slider-with-a-non-linear-scale */ -static double expScale(double inputValue, double midValue, double maxValue) -{ - double returnValue = 0; - double M = maxValue / midValue; - double C = log(pow(M - 1, 2)); - double B = maxValue / (exp(C) - 1); - double A = -1 * B; - - returnValue = A + B * exp(C * inputValue); - - return returnValue; -} - static void addDirectoryFilesToList(QStringList &list, QDir &dir) { QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name); @@ -922,33 +909,6 @@ finish: addPlaylistHashToGrid(items); } -/* https://gist.github.com/andrey-str/0f9c7709cbf0c9c49ef9 */ -static void setElidedText(QLabel *label, QWidget *clipWidget, int padding, const QString &text) -{ - QFontMetrics metrix(label->font()); - int width = clipWidget->width() - padding; - QString clippedText = metrix.elidedText(text, Qt::ElideRight, width); - label->setText(clippedText); -} - -inline void MainWindow::calcGridItemSize(GridItem *item, int zoomValue) -{ - int newSize = 0; - QLabel *label = NULL; - - if (zoomValue < 50) - newSize = expScale(lerp(0, 49, 25, 49, zoomValue) / 50.0, 102, 256); - else - newSize = expScale(zoomValue / 100.0, 256, 1024); - - item->widget->setFixedSize(QSize(newSize, newSize)); - - label = item->widget->findChild("thumbnailQLabel"); - - if (label) - setElidedText(label, item->widget, item->widget->layout()->contentsMargins().left() + item->widget->layout()->spacing() + 2, item->labelText); -} - void MainWindow::addPlaylistHashToGrid(const QVector > &items) { QScreen *screen = qApp->primaryScreen(); diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 460e7542ad..d36d27dfd7 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -138,6 +138,28 @@ static void scan_finished_handler(void *task_data, void *user_data, const char * } #endif +static double expScale(double inputValue, double midValue, double maxValue) +{ + double returnValue = 0; + double M = maxValue / midValue; + double C = log(pow(M - 1, 2)); + double B = maxValue / (exp(C) - 1); + double A = -1 * B; + + returnValue = A + B * exp(C * inputValue); + + return returnValue; +} + +/* https://gist.github.com/andrey-str/0f9c7709cbf0c9c49ef9 */ +static void setElidedText(QLabel *label, QWidget *clipWidget, int padding, const QString &text) +{ + QFontMetrics metrix(label->font()); + int width = clipWidget->width() - padding; + QString clippedText = metrix.elidedText(text, Qt::ElideRight, width); + label->setText(clippedText); +} + GridItem::GridItem() : QObject() ,widget(NULL) @@ -926,6 +948,24 @@ void MainWindow::onListViewClicked() onCurrentListItemChanged(m_listWidget->currentItem(), NULL); } +void MainWindow::calcGridItemSize(GridItem *item, int zoomValue) +{ + int newSize = 0; + QLabel *label = NULL; + + if (zoomValue < 50) + newSize = expScale(lerp(0, 49, 25, 49, zoomValue) / 50.0, 102, 256); + else + newSize = expScale(zoomValue / 100.0, 256, 1024); + + item->widget->setFixedSize(QSize(newSize, newSize)); + + label = item->widget->findChild("thumbnailQLabel"); + + if (label) + setElidedText(label, item->widget, item->widget->layout()->contentsMargins().left() + item->widget->layout()->spacing() + 2, item->labelText); +} + void MainWindow::onZoomValueChanged(int value) { int i; From e2ff7478ca68ace23f20393a8ccdb946662a5ba0 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Fri, 17 Aug 2018 07:49:25 -0400 Subject: [PATCH 059/182] don't return uninitialized data --- gfx/drivers/gl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index f47cc488c4..b6a919108c 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -380,7 +380,7 @@ static bool gl_shader_init(gl_t *gl, const gfx_ctx_driver_t *ctx_driver, video_shader_ctx_init_t init_data; enum rarch_shader_type type = DEFAULT_SHADER_TYPE; const char *shader_path = retroarch_get_shader_preset(); - + if (shader_path) { type = video_shader_parse_type(shader_path, @@ -839,7 +839,7 @@ static void gl_show_mouse(void *data, bool state) static struct video_shader *gl_get_current_shader(void *data) { - video_shader_ctx_t shader_info; + video_shader_ctx_t shader_info = {0}; video_shader_driver_direct_get_current_shader(&shader_info); @@ -1798,9 +1798,9 @@ static void *gl_init(const video_info_t *video, } if (!renderchain_gl_init_first(&gl->renderchain_driver, - &gl->renderchain_data)) + &gl->renderchain_data)) { - RARCH_ERR("[GL]: Renderchain could not be initialized.\n"); + RARCH_ERR("[GL]: Renderchain could not be initialized.\n"); goto error; } From 7250181319d415395e1e1a0a4ea656a24e4f19f8 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 17 Aug 2018 14:50:56 +0200 Subject: [PATCH 060/182] Add some __WINRT__ ifdefs --- config.features.h | 2 ++ gfx/common/win32_common.h | 2 ++ libretro-common/file/nbio/nbio_windowsmmap.c | 2 +- ui/drivers/ui_win32.c | 3 ++- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/config.features.h b/config.features.h index f05836d122..a9175e74f9 100644 --- a/config.features.h +++ b/config.features.h @@ -356,6 +356,8 @@ static const bool _avfoundation_supp = false; #else #define GLOBAL_CONFIG_DIR "/etc" #endif +#else +#define GLOBAL_CONFIG_DIR "" #endif #endif diff --git a/gfx/common/win32_common.h b/gfx/common/win32_common.h index f03940ce9d..04eeeef936 100644 --- a/gfx/common/win32_common.h +++ b/gfx/common/win32_common.h @@ -63,12 +63,14 @@ void create_gdi_context(HWND hwnd, bool *quit); bool gdi_has_menu_frame(void); +#if !defined(__WINRT__) bool win32_window_init(WNDCLASSEX *wndclass, bool fullscreen, const char *class_name); void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use, unsigned *width, unsigned *height, bool fullscreen, bool windowed_full, RECT *rect, RECT *mon_rect, DWORD *style); #endif +#endif void win32_monitor_from_window(void); diff --git a/libretro-common/file/nbio/nbio_windowsmmap.c b/libretro-common/file/nbio/nbio_windowsmmap.c index 2bfd834a71..67860a3909 100644 --- a/libretro-common/file/nbio/nbio_windowsmmap.c +++ b/libretro-common/file/nbio/nbio_windowsmmap.c @@ -22,7 +22,7 @@ #include -#if defined(_WIN32) && !defined(_XBOX) +#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) #include #include diff --git a/ui/drivers/ui_win32.c b/ui/drivers/ui_win32.c index aa3b075359..3811f365ae 100644 --- a/ui/drivers/ui_win32.c +++ b/ui/drivers/ui_win32.c @@ -57,6 +57,7 @@ typedef struct ui_companion_win32 void *empty; } ui_companion_win32_t; +#ifndef __WINRT__ bool win32_window_init(WNDCLASSEX *wndclass, bool fullscreen, const char *class_name) { @@ -79,7 +80,7 @@ bool win32_window_init(WNDCLASSEX *wndclass, return true; } - +#endif static bool win32_browser( HWND owner, From 1fba7df85970c0fd1ce613691daa5a6b2d012101 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Fri, 17 Aug 2018 09:40:02 -0400 Subject: [PATCH 061/182] use existing src folder for android64 instead of duplicating it --- pkg/android/phoenix64/ant.properties | 2 +- .../browser/mainmenu/MainMenuActivity.java | 200 ----------- .../browser/preferences/util/ConfigFile.java | 281 ---------------- .../preferences/util/UserPreferences.java | 300 ----------------- .../retroactivity/RetroActivityCamera.java | 225 ------------- .../retroactivity/RetroActivityCommon.java | 141 -------- .../retroactivity/RetroActivityFuture.java | 87 ----- .../retroactivity/RetroActivityIntent.java | 105 ------ .../retroactivity/RetroActivityLocation.java | 316 ------------------ .../retroactivity/RetroActivityPast.java | 7 - 10 files changed, 1 insertion(+), 1663 deletions(-) delete mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/mainmenu/MainMenuActivity.java delete mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/ConfigFile.java delete mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/UserPreferences.java delete mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java delete mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java delete mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java delete mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java delete mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java delete mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityPast.java diff --git a/pkg/android/phoenix64/ant.properties b/pkg/android/phoenix64/ant.properties index b0971e891e..97d04e9d39 100644 --- a/pkg/android/phoenix64/ant.properties +++ b/pkg/android/phoenix64/ant.properties @@ -14,4 +14,4 @@ # 'key.store' for the location of your keystore and # 'key.alias' for the name of the key to use. # The password will be asked during the build when you use the 'release' target. - +source.dir=../phoenix/src diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/mainmenu/MainMenuActivity.java b/pkg/android/phoenix64/src/com/retroarch/browser/mainmenu/MainMenuActivity.java deleted file mode 100644 index 102dffdf50..0000000000 --- a/pkg/android/phoenix64/src/com/retroarch/browser/mainmenu/MainMenuActivity.java +++ /dev/null @@ -1,200 +0,0 @@ -package com.retroarch.browser.mainmenu; - -import com.retroarch.browser.preferences.util.UserPreferences; -import com.retroarch.browser.retroactivity.RetroActivityFuture; -import com.retroarch.browser.retroactivity.RetroActivityPast; - -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.media.AudioManager; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.preference.PreferenceActivity; -import android.preference.PreferenceManager; -import android.provider.Settings; - -import java.util.List; -import java.util.ArrayList; -import android.content.pm.PackageManager; -import android.Manifest; -import android.content.DialogInterface; -import android.app.AlertDialog; -import android.util.Log; - -/** - * {@link PreferenceActivity} subclass that provides all of the - * functionality of the main menu screen. - */ -public final class MainMenuActivity extends PreferenceActivity -{ - final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124; - boolean checkPermissions = false; - - public void showMessageOKCancel(String message, DialogInterface.OnClickListener onClickListener) - { - new AlertDialog.Builder(this).setMessage(message) - .setPositiveButton("OK", onClickListener).setCancelable(false) - .setNegativeButton("Cancel", null).create().show(); - } - - private boolean addPermission(List permissionsList, String permission) - { - if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) - { - permissionsList.add(permission); - - // Check for Rationale Option - if (!shouldShowRequestPermissionRationale(permission)) - return false; - } - - return true; - } - - public void checkRuntimePermissions() - { - if (android.os.Build.VERSION.SDK_INT >= 23) - { - // Android 6.0+ needs runtime permission checks - List permissionsNeeded = new ArrayList(); - final List permissionsList = new ArrayList(); - - if (!addPermission(permissionsList, Manifest.permission.READ_EXTERNAL_STORAGE)) - permissionsNeeded.add("Read External Storage"); - if (!addPermission(permissionsList, Manifest.permission.WRITE_EXTERNAL_STORAGE)) - permissionsNeeded.add("Write External Storage"); - - if (permissionsList.size() > 0) - { - checkPermissions = true; - - if (permissionsNeeded.size() > 0) - { - // Need Rationale - Log.i("MainMenuActivity", "Need to request external storage permissions."); - - String message = "You need to grant access to " + permissionsNeeded.get(0); - - for (int i = 1; i < permissionsNeeded.size(); i++) - message = message + ", " + permissionsNeeded.get(i); - - showMessageOKCancel(message, - new DialogInterface.OnClickListener() - { - @Override - public void onClick(DialogInterface dialog, int which) - { - if (which == AlertDialog.BUTTON_POSITIVE) - { - requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), - REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS); - - Log.i("MainMenuActivity", "User accepted request for external storage permissions."); - } - } - }); - } - else - { - requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), - REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS); - - Log.i("MainMenuActivity", "Requested external storage permissions."); - } - } - } - - if (!checkPermissions) - { - finalStartup(); - } - } - - public void finalStartup() - { - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - Intent retro; - - if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) - { - retro = new Intent(this, RetroActivityFuture.class); - } - else - { - retro = new Intent(this, RetroActivityPast.class); - } - - retro.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - - startRetroActivity( - retro, - null, - prefs.getString("libretro_path", getApplicationInfo().dataDir + "/cores/"), - UserPreferences.getDefaultConfigPath(this), - Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD), - getApplicationInfo().dataDir, - getApplicationInfo().sourceDir); - startActivity(retro); - finish(); - } - - @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) - { - switch (requestCode) - { - case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: - for (int i = 0; i < permissions.length; i++) - { - if(grantResults[i] == PackageManager.PERMISSION_GRANTED) - { - Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was granted."); - } - else - { - Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was not granted."); - } - } - - break; - default: - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - break; - } - - finalStartup(); - } - - public static void startRetroActivity(Intent retro, String contentPath, String corePath, - String configFilePath, String imePath, String dataDirPath, String dataSourcePath) - { - if (contentPath != null) { - retro.putExtra("ROM", contentPath); - } - retro.putExtra("LIBRETRO", corePath); - retro.putExtra("CONFIGFILE", configFilePath); - retro.putExtra("IME", imePath); - retro.putExtra("DATADIR", dataDirPath); - retro.putExtra("APK", dataSourcePath); - retro.putExtra("SDCARD", Environment.getExternalStorageDirectory().getAbsolutePath()); - retro.putExtra("DOWNLOADS", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()); - retro.putExtra("SCREENSHOTS", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()); - String external = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/com.retroarch.aarch64/files"; - retro.putExtra("EXTERNAL", external); - } - - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - // Bind audio stream to hardware controls. - setVolumeControlStream(AudioManager.STREAM_MUSIC); - - UserPreferences.updateConfigFile(this); - - checkRuntimePermissions(); - } -} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/ConfigFile.java b/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/ConfigFile.java deleted file mode 100644 index eccaf730cb..0000000000 --- a/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/ConfigFile.java +++ /dev/null @@ -1,281 +0,0 @@ -package com.retroarch.browser.preferences.util; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.Map; - -import android.util.Log; - -/** - * Represents a configuration file that works off of a key-value pair - * in the form [key name] = "[value]". - */ -public final class ConfigFile -{ - // Map containing all of the key-value pairs. - private final HashMap map = new HashMap(); - - /** - * Constructor - */ - public ConfigFile() - { - } - - /** - * Constructor - * - * @param filePath The path to the configuration file to open. - */ - public ConfigFile(String filePath) - { - if (filePath == null) - throw new IllegalArgumentException("filePath cannot be null."); - - try - { - open(filePath); - } - catch (IOException ioe) - { - Log.e("ConfigFile", "Stream reading the configuration file was suddenly closed for an unknown reason."); - } - } - - /** - * Parses a configuration file from the given stream - * and appends the parsed values to the key-value map. - * - * @param stream The {@link InputStream} containing the configuration file to parse. - */ - public void append(InputStream stream) throws IOException - { - BufferedReader br = new BufferedReader(new InputStreamReader(stream)); - - String line; - while ((line = br.readLine()) != null) - parseLine(line); - - br.close(); - } - - /** - * Opens a configuration file given by configPath - * and parses all of its key-value pairs, adding - * them to the key-value map. - * - * @param configPath Path to the configuration file to parse. - */ - public void open(String configPath) throws IOException - { - clear(); - append(new FileInputStream(configPath)); - } - - private void parseLine(String line) - { - String[] tokens = line.split("=", 2); - if (tokens.length < 2) - return; - - for (int i = 0; i < tokens.length; i++) - tokens[i] = tokens[i].trim(); - - String key = tokens[0]; - String value = tokens[1]; - - if (value.startsWith("\"")) - value = value.substring(1, value.lastIndexOf('\"')); - else - value = value.split(" ")[0]; - - if (value.length() > 0) - map.put(key, value); - } - - /** - * Clears the key-value map of all currently set keys and values. - */ - public void clear() - { - map.clear(); - } - - /** - * Writes the currently set key-value pairs to - * - * @param path The path to save the - * - * @throws IOException - */ - public void write(String path) throws IOException - { - PrintWriter writer = new PrintWriter(path); - - for (Map.Entry entry : map.entrySet()) - { - writer.println(entry.getKey() + " = \"" + entry.getValue() + "\""); - } - - writer.close(); - } - - /** - * Checks if a key exists in the {@link HashMap} - * backing this ConfigFile instance. - * - * @param key The key to check for. - * - * @return true if the key exists in the HashMap backing - * this ConfigFile; false if it doesn't. - */ - public boolean keyExists(String key) - { - return map.containsKey(key); - } - - /** - * Sets a key to the given String value. - * - * @param key The key to set the String value to. - * @param value The String value to set to the key. - */ - public void setString(String key, String value) - { - map.put(key, value); - } - - /** - * Sets a key to the given boolean value. - * - * @param key The key to set the boolean value to. - * @param value The boolean value to set to the key. - */ - public void setBoolean(String key, boolean value) - { - map.put(key, Boolean.toString(value)); - } - - /** - * Sets a key to the given Integer value. - * - * @param key The key to set the Integer value to. - * @param value The Integer value to set to the key. - */ - public void setInt(String key, int value) - { - map.put(key, Integer.toString(value)); - } - - /** - * Sets a key to the given double value. - * - * @param key The key to set the double value to. - * @param value The double value to set to the key. - */ - public void setDouble(String key, double value) - { - map.put(key, Double.toString(value)); - } - - /** - * Sets a key to the given float value. - * - * @param key The key to set the float value to. - * @param value The float value to set to the key. - */ - public void setFloat(String key, float value) - { - map.put(key, Float.toString(value)); - } - - /** - * Gets the String value associated with the given key. - * - * @param key The key to get the String value from. - * - * @return the String object associated with the given key. - */ - public String getString(String key) - { - String ret = map.get(key); - - if (ret != null) - return ret; - else - return null; - } - - /** - * Gets the Integer value associated with the given key. - * - * @param key The key to get the Integer value from. - * - * @return the Integer value associated with the given key. - */ - public int getInt(String key) - { - String str = getString(key); - - if (str != null) - return Integer.parseInt(str); - else - throw new IllegalArgumentException("Config key '" + key + "' is invalid."); - } - - /** - * Gets the double value associated with the given key. - * - * @param key The key to get the double value from. - * - * @return the double value associated with the given key. - */ - public double getDouble(String key) - { - String str = getString(key); - - if (str != null) - return Double.parseDouble(str); - else - throw new IllegalArgumentException("Config key '" + key + "' is invalid."); - } - - /** - * Gets the float value associated with the given key. - * - * @param key The key to get the float value from. - * - * @return the float value associated with the given key. - */ - public float getFloat(String key) - { - String str = getString(key); - - if (str != null) - return Float.parseFloat(str); - else - throw new IllegalArgumentException("Config key '" + key + "' is invalid."); - } - - /** - * Gets the boolean value associated with the given key. - * - * @param key The key to get the boolean value from. - * - * @return the boolean value associated with the given key. - */ - public boolean getBoolean(String key) - { - String str = getString(key); - - if (str != null) - return Boolean.parseBoolean(str); - else - throw new IllegalArgumentException("Config key '" + key + "' is invalid."); - } -} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/UserPreferences.java b/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/UserPreferences.java deleted file mode 100644 index 2e1ec9ed61..0000000000 --- a/pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/UserPreferences.java +++ /dev/null @@ -1,300 +0,0 @@ -package com.retroarch.browser.preferences.util; - -import java.io.File; -import java.io.IOException; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.SharedPreferences; -import android.media.AudioManager; -import android.media.AudioTrack; -import android.os.Build; -import android.preference.PreferenceManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.util.Log; - -/** - * Utility class for retrieving, saving, or loading preferences. - */ -public final class UserPreferences -{ - // Logging tag. - private static final String TAG = "UserPreferences"; - - // Disallow explicit instantiation. - private UserPreferences() - { - } - - /** - * Retrieves the path to the default location of the libretro config. - * - * @param ctx the current {@link Context} - * - * @return the path to the default location of the libretro config. - */ - public static String getDefaultConfigPath(Context ctx) - { - // Internal/External storage dirs. - final String internal = ctx.getFilesDir().getAbsolutePath(); - String external = null; - - // Get the App's external storage folder - final String state = android.os.Environment.getExternalStorageState(); - if (android.os.Environment.MEDIA_MOUNTED.equals(state)) { - File extsd = ctx.getExternalFilesDir(null); - external = extsd.getAbsolutePath(); - } - - // Native library directory and data directory for this front-end. - final String dataDir = ctx.getApplicationInfo().dataDir; - final String coreDir = dataDir + "/cores/"; - - // Get libretro name and path - final SharedPreferences prefs = getPreferences(ctx); - final String libretro_path = prefs.getString("libretro_path", coreDir); - - // Check if global config is being used. Return true upon failure. - final boolean globalConfigEnabled = prefs.getBoolean("global_config_enable", true); - - String append_path; - // If we aren't using the global config. - if (!globalConfigEnabled && !libretro_path.equals(coreDir)) - { - String sanitized_name = sanitizeLibretroPath(libretro_path); - append_path = File.separator + sanitized_name + ".cfg"; - } - else // Using global config. - { - append_path = File.separator + "retroarch.cfg"; - } - - if (external != null) - { - String confPath = external + append_path; - if (new File(confPath).exists()) - return confPath; - } - else if (internal != null) - { - String confPath = internal + append_path; - if (new File(confPath).exists()) - return confPath; - } - else - { - String confPath = "/mnt/extsd" + append_path; - if (new File(confPath).exists()) - return confPath; - } - - // Config file does not exist. Create empty one. - - // emergency fallback - String new_path = "/mnt/sd" + append_path; - - if (external != null) - new_path = external + append_path; - else if (internal != null) - new_path = internal + append_path; - else if (dataDir != null) - new_path = dataDir + append_path; - - try { - new File(new_path).createNewFile(); - } - catch (IOException e) - { - Log.e(TAG, "Failed to create config file to: " + new_path); - } - return new_path; - } - - /** - * Updates the libretro configuration file - * with new values if settings have changed. - * - * @param ctx the current {@link Context}. - */ - public static void updateConfigFile(Context ctx) - { - String path = getDefaultConfigPath(ctx); - ConfigFile config = new ConfigFile(path); - - Log.i(TAG, "Writing config to: " + path); - - final String dataDir = ctx.getApplicationInfo().dataDir; - final String coreDir = dataDir + "/cores/"; - - final SharedPreferences prefs = getPreferences(ctx); - - config.setString("libretro_directory", coreDir); - config.setInt("audio_out_rate", getOptimalSamplingRate(ctx)); - - try - { - int version = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0).versionCode; - final String dst_path = dataDir; - final String dst_path_subdir = "assets"; - - Log.i(TAG, "dst dir is: " + dst_path); - Log.i(TAG, "dst subdir is: " + dst_path_subdir); - - config.setBoolean("log_verbosity", true); - config.setString("bundle_assets_src_path", ctx.getApplicationInfo().sourceDir); - config.setString("bundle_assets_dst_path", dst_path); - config.setString("bundle_assets_dst_path_subdir", dst_path_subdir); - config.setInt("bundle_assets_extract_version_current", version); - } - catch (NameNotFoundException ignored) - { - } - - // Refactor this entire mess and make this usable for per-core config - if (Build.VERSION.SDK_INT >= 17 && prefs.getBoolean("audio_latency_auto", true)) - { - config.setInt("audio_block_frames", getLowLatencyBufferSize(ctx)); - } - - try - { - config.write(path); - } - catch (IOException e) - { - Log.e(TAG, "Failed to save config file to: " + path); - } - } - - private static void readbackString(ConfigFile cfg, SharedPreferences.Editor edit, String key) - { - if (cfg.keyExists(key)) - edit.putString(key, cfg.getString(key)); - else - edit.remove(key); - } - - private static void readbackBool(ConfigFile cfg, SharedPreferences.Editor edit, String key) - { - if (cfg.keyExists(key)) - edit.putBoolean(key, cfg.getBoolean(key)); - else - edit.remove(key); - } - - private static void readbackDouble(ConfigFile cfg, SharedPreferences.Editor edit, String key) - { - if (cfg.keyExists(key)) - edit.putFloat(key, (float)cfg.getDouble(key)); - else - edit.remove(key); - } - - /* - private static void readbackFloat(ConfigFile cfg, SharedPreferences.Editor edit, String key) - { - if (cfg.keyExists(key)) - edit.putFloat(key, cfg.getFloat(key)); - else - edit.remove(key); - } - */ - - /** - private static void readbackInt(ConfigFile cfg, SharedPreferences.Editor edit, String key) - { - if (cfg.keyExists(key)) - edit.putInt(key, cfg.getInt(key)); - else - edit.remove(key); - } - */ - - /** - * Sanitizes a libretro core path. - * - * @param path The path to the libretro core. - * - * @return the sanitized libretro path. - */ - private static String sanitizeLibretroPath(String path) - { - String sanitized_name = path.substring( - path.lastIndexOf('/') + 1, - path.lastIndexOf('.')); - sanitized_name = sanitized_name.replace("neon", ""); - sanitized_name = sanitized_name.replace("libretro_", ""); - - return sanitized_name; - } - - /** - * Gets a {@link SharedPreferences} instance containing current settings. - * - * @param ctx the current {@link Context}. - * - * @return A SharedPreference instance containing current settings. - */ - public static SharedPreferences getPreferences(Context ctx) - { - return PreferenceManager.getDefaultSharedPreferences(ctx); - } - - /** - * Gets the optimal sampling rate for low-latency audio playback. - * - * @param ctx the current {@link Context}. - * - * @return the optimal sampling rate for low-latency audio playback in Hz. - */ - @TargetApi(17) - private static int getLowLatencyOptimalSamplingRate(Context ctx) - { - AudioManager manager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE); - - return Integer.parseInt(manager - .getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)); - } - - /** - * Gets the optimal buffer size for low-latency audio playback. - * - * @param ctx the current {@link Context}. - * - * @return the optimal output buffer size in decimal PCM frames. - */ - @TargetApi(17) - private static int getLowLatencyBufferSize(Context ctx) - { - AudioManager manager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE); - int buffersize = Integer.parseInt(manager - .getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER)); - Log.i(TAG, "Queried ideal buffer size (frames): " + buffersize); - return buffersize; - } - - /** - * Gets the optimal audio sampling rate. - *

- * On Android 4.2+ devices this will retrieve the optimal low-latency sampling rate, - * since Android 4.2 adds support for low latency audio in general. - *

- * On other devices, it simply returns the regular optimal sampling rate - * as returned by the hardware. - * - * @param ctx The current {@link Context}. - * - * @return the optimal audio sampling rate in Hz. - */ - private static int getOptimalSamplingRate(Context ctx) - { - int ret; - if (Build.VERSION.SDK_INT >= 17) - ret = getLowLatencyOptimalSamplingRate(ctx); - else - ret = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC); - - Log.i(TAG, "Using sampling rate: " + ret + " Hz"); - return ret; - } -} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java deleted file mode 100644 index d51d7f768f..0000000000 --- a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java +++ /dev/null @@ -1,225 +0,0 @@ -package com.retroarch.browser.retroactivity; - -import java.io.IOException; - -import com.retroarch.browser.preferences.util.UserPreferences; - -import android.annotation.SuppressLint; -import android.content.SharedPreferences; -import android.graphics.SurfaceTexture; -import android.graphics.SurfaceTexture.OnFrameAvailableListener; -import android.hardware.Camera; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; - -//For Android 3.0 and up - -/** - * Class which provides {@link Camera} functionality - * to {@link RetroActivityFuture}. - */ -@SuppressLint("NewApi") -public class RetroActivityCamera extends RetroActivityCommon -{ - private Camera mCamera = null; - private long lastTimestamp = 0; - private SurfaceTexture texture; - private boolean updateSurface = true; - private boolean camera_service_running = false; - - /** - * Executed when the {@link Camera} - * is staring to capture. - */ - public void onCameraStart() - { - if (camera_service_running) - return; - - if (mCamera != null) - mCamera.startPreview(); - camera_service_running = true; - } - - /** - * Executed when the {@link Camera} is done capturing. - *

- * Note that this does not release the currently held - * {@link Camera} instance and must be freed by calling - * {@link #onCameraFree} - */ - public void onCameraStop() - { - if (!camera_service_running) - return; - - if (mCamera != null) - mCamera.stopPreview(); - camera_service_running = false; - } - - /** - * Releases the currently held {@link Camera} instance. - */ - public void onCameraFree() - { - onCameraStop(); - - if (mCamera != null) - mCamera.release(); - } - - /** - * Initializes the camera for use. - */ - public void onCameraInit() - { - if (mCamera != null) - return; - - mCamera = Camera.open(); - } - - /** - * Polls the camera for updates to the {@link SurfaceTexture}. - * - * @return true if polling was successful, false otherwise. - */ - public boolean onCameraPoll() - { - if (!camera_service_running) - return false; - - if (texture == null) - { - Log.i("RetroActivity", "No texture"); - return true; - } - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) - { - if (updateSurface) - { - texture.updateTexImage(); - } - - long newTimestamp = texture.getTimestamp(); - - if (newTimestamp != lastTimestamp) - { - lastTimestamp = newTimestamp; - return true; - } - - return false; - } - - return true; - } - - /** - * Initializes the {@link SurfaceTexture} used by the - * {@link Camera} with a given OpenGL texure ID. - * - * @param gl_texid texture ID to initialize the - * {@link SurfaceTexture} with. - */ - public void onCameraTextureInit(int gl_texid) - { - texture = new SurfaceTexture(gl_texid); - texture.setOnFrameAvailableListener(onCameraFrameAvailableListener); - } - - /** - * Sets the {@link Camera} texture with the texture represented - * by the given OpenGL texture ID. - * - * @param gl_texid The texture ID representing the texture to set the camera to. - * @throws IOException If setting the texture fails. - */ - public void onCameraSetTexture(int gl_texid) throws IOException - { - if (texture == null) - onCameraTextureInit(gl_texid); - - if (mCamera != null) - mCamera.setPreviewTexture(texture); - } - - private final OnFrameAvailableListener onCameraFrameAvailableListener = new OnFrameAvailableListener() - { - @Override - public void onFrameAvailable(SurfaceTexture surfaceTexture) - { - updateSurface = true; - } - }; - - @Override - public void onCreate(Bundle savedInstanceState) - { - // Save the current setting for updates - SharedPreferences prefs = UserPreferences.getPreferences(this); - SharedPreferences.Editor edit = prefs.edit(); - edit.putBoolean("CAMERA_UPDATES_ON", false); - edit.apply(); - - camera_service_running = false; - - super.onCreate(savedInstanceState); - } - - @Override - public void onPause() - { - // Save the current setting for updates - SharedPreferences prefs = UserPreferences.getPreferences(this); - SharedPreferences.Editor edit = prefs.edit(); - edit.putBoolean("CAMERA_UPDATES_ON", camera_service_running); - edit.apply(); - - onCameraStop(); - super.onPause(); - } - - @Override - public void onResume() - { - SharedPreferences prefs = UserPreferences.getPreferences(this); - SharedPreferences.Editor edit = prefs.edit(); - - /* - * Get any previous setting for camera updates - * Gets "false" if an error occurs - */ - if (prefs.contains("CAMERA_UPDATES_ON")) - { - camera_service_running = prefs.getBoolean("CAMERA_UPDATES_ON", false); - if (camera_service_running) - { - onCameraStart(); - } - } - else // Otherwise, turn off camera updates - { - edit.putBoolean("CAMERA_UPDATES_ON", false); - edit.apply(); - camera_service_running = false; - } - super.onResume(); - } - - @Override - public void onDestroy() - { - onCameraFree(); - super.onDestroy(); - } - - @Override - public void onStop() - { - onCameraStop(); - super.onStop(); - } -} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java deleted file mode 100644 index e660dd2eb9..0000000000 --- a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.retroarch.browser.retroactivity; - -import com.retroarch.browser.preferences.util.UserPreferences; -import android.annotation.TargetApi; -import android.content.res.Configuration; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.app.UiModeManager; -import android.os.BatteryManager; -import android.os.Build; -import android.os.PowerManager; -import android.util.Log; - -import java.util.concurrent.CountDownLatch; - -/** - * Class which provides common methods for RetroActivity related classes. - */ -public class RetroActivityCommon extends RetroActivityLocation -{ - public static int FRONTEND_POWERSTATE_NONE = 0; - public static int FRONTEND_POWERSTATE_NO_SOURCE = 1; - public static int FRONTEND_POWERSTATE_CHARGING = 2; - public static int FRONTEND_POWERSTATE_CHARGED = 3; - public static int FRONTEND_POWERSTATE_ON_POWER_SOURCE = 4; - public boolean sustainedPerformanceMode = true; - - // Exiting cleanly from NDK seems to be nearly impossible. - // Have to use exit(0) to avoid weird things happening, even with runOnUiThread() approaches. - // Use a separate JNI function to explicitly trigger the readback. - public void onRetroArchExit() - { - finish(); - } - - @TargetApi(24) - public void setSustainedPerformanceMode(boolean on) - { - sustainedPerformanceMode = on; - - if (Build.VERSION.SDK_INT >= 24) { - if (isSustainedPerformanceModeSupported()) { - final CountDownLatch latch = new CountDownLatch(1); - - runOnUiThread(new Runnable() { - @Override - public void run() { - Log.i("RetroActivity", "setting sustained performance mode to " + sustainedPerformanceMode); - - getWindow().setSustainedPerformanceMode(sustainedPerformanceMode); - - latch.countDown(); - } - }); - - try { - latch.await(); - }catch(InterruptedException e) { - e.printStackTrace(); - } - } - } - } - - @TargetApi(24) - public boolean isSustainedPerformanceModeSupported() - { - boolean supported = false; - - if (Build.VERSION.SDK_INT >= 24) - { - PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE); - - if (powerManager.isSustainedPerformanceModeSupported()) - supported = true; - } - - - Log.i("RetroActivity", "isSustainedPerformanceModeSupported? " + supported); - - return supported; - } - - public int getBatteryLevel() - { - IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); - // This doesn't actually register anything (or need to) because we know this particular intent is sticky and we do not specify a BroadcastReceiver anyway - Intent batteryStatus = registerReceiver(null, ifilter); - int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); - int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, 100); - - float percent = ((float)level / (float)scale) * 100.0f; - - Log.i("RetroActivity", "battery: level = " + level + ", scale = " + scale + ", percent = " + percent); - - return (int)percent; - } - - public int getPowerstate() - { - IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); - // This doesn't actually register anything (or need to) because we know this particular intent is sticky and we do not specify a BroadcastReceiver anyway - Intent batteryStatus = registerReceiver(null, ifilter); - int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); - boolean hasBattery = batteryStatus.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false); - boolean isCharging = (status == BatteryManager.BATTERY_STATUS_CHARGING); - boolean isCharged = (status == BatteryManager.BATTERY_STATUS_FULL); - int powerstate = FRONTEND_POWERSTATE_NONE; - - if (isCharged) - powerstate = FRONTEND_POWERSTATE_CHARGED; - else if (isCharging) - powerstate = FRONTEND_POWERSTATE_CHARGING; - else if (!hasBattery) - powerstate = FRONTEND_POWERSTATE_NO_SOURCE; - else - powerstate = FRONTEND_POWERSTATE_ON_POWER_SOURCE; - - Log.i("RetroActivity", "power state = " + powerstate); - - return powerstate; - } - - public boolean isAndroidTV() - { - Configuration config = getResources().getConfiguration(); - UiModeManager uiModeManager = (UiModeManager)getSystemService(UI_MODE_SERVICE); - - if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) - { - Log.i("RetroActivity", "isAndroidTV == true"); - return true; - } - else - { - Log.i("RetroActivity", "isAndroidTV == false"); - return false; - } - } -} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java deleted file mode 100644 index eba29872a6..0000000000 --- a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.retroarch.browser.retroactivity; - -import android.view.View; -import android.view.WindowManager; -import android.content.Intent; -import android.content.Context; -import android.hardware.input.InputManager; -import android.os.Build; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public final class RetroActivityFuture extends RetroActivityCamera { - - // If set to true then Retroarch will completely exit when it loses focus - private boolean quitfocus = false; - - @Override - public void onResume() { - super.onResume(); - - setSustainedPerformanceMode(sustainedPerformanceMode); - - if (Build.VERSION.SDK_INT >= 19) { - // Immersive mode - - // Constants from API > 14 - final int API_SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; - final int API_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; - final int API_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; - final int API_SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; - final int API_SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; - - View thisView = getWindow().getDecorView(); - thisView.setSystemUiVisibility(API_SYSTEM_UI_FLAG_LAYOUT_STABLE - | API_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | API_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | API_SYSTEM_UI_FLAG_FULLSCREEN - | API_SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - - // Check for Android UI specific parameters - Intent retro = getIntent(); - String refresh = retro.getStringExtra("REFRESH"); - - // If REFRESH parameter is provided then try to set refreshrate accordingly - if(refresh != null) { - WindowManager.LayoutParams params = getWindow().getAttributes(); - params.preferredRefreshRate = Integer.parseInt(refresh); - getWindow().setAttributes(params); - } - - // If QUITFOCUS parameter is provided then enable that Retroarch quits when focus is lost - quitfocus = retro.hasExtra("QUITFOCUS"); - - // If HIDEMOUSE parameters is provided then hide the mourse cursor - // This requires NVIDIA Android extensions (available on NVIDIA Shield), if they are not - // available then nothing will be done - if (retro.hasExtra("HIDEMOUSE")) hideMouseCursor(); - } - } - - public void hideMouseCursor() { - - // Check for NVIDIA extensions and minimum SDK version - Method mInputManager_setCursorVisibility; - try { mInputManager_setCursorVisibility = - InputManager.class.getMethod("setCursorVisibility", boolean.class); - } - catch (NoSuchMethodException ex) { - return; // Extensions were not available so do nothing - } - - // Hide the mouse cursor - InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE); - try { mInputManager_setCursorVisibility.invoke(inputManager, false); } - catch (InvocationTargetException ite) { } - catch (IllegalAccessException iae) { } - } - - @Override - public void onStop() { - super.onStop(); - - // If QUITFOCUS parameter was set then completely exit Retroarch when focus is lost - if (quitfocus) System.exit(0); - } -} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java deleted file mode 100644 index 91ccc3f8a6..0000000000 --- a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.retroarch.browser.retroactivity; - -import com.retroarch.browser.mainmenu.MainMenuActivity; - -import android.content.Intent; -import android.util.Log; - -public class RetroActivityIntent extends RetroActivityCommon { - private Intent pendingIntent = null; - private static final String TAG = "RetroArch"; - - @Override - public void onBackPressed() - { - Log.i("RetroActivity", "onBackKeyPressed"); - Intent retro = new Intent(this, MainMenuActivity.class); - retro.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivity(retro); - } - - @Override - public void onNewIntent(Intent intent) - { - Log.i("RetroActivity", "onNewIntent invoked."); - super.onNewIntent(intent); - setIntent(intent); - pendingIntent = intent; - } - - /** - * Gets the ROM file specified in the pending intent. - * - * @return the ROM file specified in the pending intent. - */ - public String getPendingIntentFullPath() - { - return pendingIntent.getStringExtra("ROM"); - } - - /** - * Gets the specified path to the libretro core in the pending intent. - * - * @return the specified path to the libretro core in the pending intent. - */ - public String getPendingIntentLibretroPath() - { - return pendingIntent.getStringExtra("LIBRETRO"); - } - - /** - * Gets the path specified in the pending intent to the retroarch cfg file. - * - * @return the path specified in the pending intent to the retroarch cfg file. - */ - public String getPendingIntentConfigPath() - { - return pendingIntent.getStringExtra("CONFIGFILE"); - } - - public String getPendingIntentStorageLocation() - { - return pendingIntent.getStringExtra("SDCARD"); - } - - public String getPendingIntentDownloadLocation() - { - return pendingIntent.getStringExtra("DOWNLOADS"); - } - - public String getPendingIntentScreenshotsLocation() - { - return pendingIntent.getStringExtra("SCREENSHOTS"); - } - - /** - * Gets the specified IME in the pending intent. - * - * @return the specified IME in the pending intent. - */ - public String getPendingIntentIME() - { - return pendingIntent.getStringExtra("IME"); - } - - /** - * Checks whether or not a pending intent exists. - * - * @return true if a pending intent exists, false otherwise. - */ - public boolean hasPendingIntent() - { - if (pendingIntent == null) - return false; - - return true; - } - - /** - * Clears the current pending intent. - */ - public void clearPendingIntent() - { - pendingIntent = null; - } -} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java deleted file mode 100644 index 9fedbf2e7b..0000000000 --- a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java +++ /dev/null @@ -1,316 +0,0 @@ -package com.retroarch.browser.retroactivity; - -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks; -import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener; -import com.google.android.gms.location.LocationClient; -import com.google.android.gms.location.LocationListener; -import com.google.android.gms.location.LocationRequest; -import com.retroarch.browser.preferences.util.UserPreferences; - -import android.app.NativeActivity; -import android.content.IntentSender; -import android.content.SharedPreferences; -import android.location.Location; -import android.os.Bundle; -import android.util.Log; -import android.widget.Toast; - -/** - * Class that implements location-based functionality for - * the {@link RetroActivityFuture} and {@link RetroActivityPast} - * activities. - */ -public class RetroActivityLocation extends NativeActivity -implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener -{ - /* LOCATION VARIABLES */ - private static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 0; - private LocationClient mLocationClient = null; - private Location mCurrentLocation; - - // Define an object that holds accuracy and frequency parameters - LocationRequest mLocationRequest = null; - boolean mUpdatesRequested = false; - boolean locationChanged = false; - boolean location_service_running = false; - - /** - * Called by Location Services when the request to connect the - * client finishes successfully. At this point, you can - * request the current location or start periodic updates - */ - @Override - public void onConnected(Bundle dataBundle) - { - if (mLocationClient == null) - return; - - // Display the connection status - Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show(); - location_service_running = true; - - // If already requested, start periodic updates - if (mUpdatesRequested) - { - mLocationClient.requestLocationUpdates(mLocationRequest, this, null); - } - else - { - // Get last known location - mCurrentLocation = mLocationClient.getLastLocation(); - locationChanged = true; - } - } - - /** - * Called by Location Services if the connection to the - * location client drops because of an error. - */ - @Override - public void onDisconnected() - { - if (mLocationClient == null) - return; - - // Display the connection status - Toast.makeText(this, "Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show(); - - // If the client is connected - if (mLocationClient.isConnected()) - { - /* - * Remove location updates for a listener. - * The current Activity is the listener, so - * the argument is "this". - */ - mLocationClient.removeLocationUpdates(this); - } - - location_service_running = false; - } - - /** - * Called by Location Services if the attempt to - * Location Services fails. - */ - @Override - public void onConnectionFailed(ConnectionResult connectionResult) - { - /* - * Google Play services can resolve some errors it detects. - * If the error has a resolution, try sending an Intent to - * start a Google Play services activity that can resolve - * error. - */ - if (connectionResult.hasResolution()) - { - try - { - // Start an Activity that tries to resolve the error - connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST); - } - catch (IntentSender.SendIntentException e) - { - // Thrown if Google Play services cancelled the original PendingIntent - e.printStackTrace(); - } - } - else - { - /* - * If no resolution is available, display a dialog to the - * user with the error. - */ - Log.e("Connection failed", "error code: " + connectionResult.getErrorCode()); - } - } - - /** - * Sets the update interval at which location-based updates - * should occur - */ - public void onLocationSetInterval(int update_interval_in_ms, int distance_interval) - { - // Use high accuracy - if (mLocationRequest == null) - return; - - mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); - - if (update_interval_in_ms == 0) - mLocationRequest.setInterval(5 * 1000); // 5 seconds - else - mLocationRequest.setInterval(update_interval_in_ms); - - // Set the fastest update interval to 1 second - mLocationRequest.setFastestInterval(1000); - } - - /** - * Initializing methods for location based functionality. - */ - public void onLocationInit() - { - /* - * Create a new location client, using the enclosing class to - * handle callbacks. - */ - if (mLocationClient == null) - mLocationClient = new LocationClient(this, this, this); - - // Start with updates turned off - mUpdatesRequested = false; - - // Create the LocationRequest object - if (mLocationRequest == null) - mLocationRequest = LocationRequest.create(); - - onLocationSetInterval(0, 0); - } - - - /** - * Executed upon starting the {@link LocationClient}. - */ - public void onLocationStart() - { - if (mLocationClient == null) - return; - - mUpdatesRequested = true; - - // Connect the client. - mLocationClient.connect(); - } - - /** - * Free up location services resources. - */ - public void onLocationFree() - { - /* TODO/FIXME */ - } - - /** - * Executed upon stopping the location client. - * Does nothing if called when the client is not started. - */ - public void onLocationStop() - { - // Disconnecting the client invalidates it. - if (mLocationClient != null && mUpdatesRequested) - mLocationClient.disconnect(); - } - - /** - * Gets the latitude at the current location in degrees. - * - * @return the latitude at the current location. - */ - public double onLocationGetLatitude() - { - return mCurrentLocation.getLatitude(); - } - - /** - * Gets the longitude at the current location in degrees. - * - * @return the longitude at the current location. - */ - public double onLocationGetLongitude() - { - return mCurrentLocation.getLongitude(); - } - - /** - * Gets the horizontal accuracy of the current location - * in meters. (NOTE: There seems to be no vertical accuracy - * for a given location with the Android location API) - * - * @return the horizontal accuracy of the current position. - */ - public double onLocationGetHorizontalAccuracy() - { - return mCurrentLocation.getAccuracy(); - } - - /** - * Tells us whether the location listener callback has - * updated the current location since the last time - * we polled. - * - * @return true if location has changed, false if location has not changed. - */ - public boolean onLocationHasChanged() - { - boolean hasChanged = locationChanged; - - // Reset flag - if (hasChanged) - locationChanged = false; - - return hasChanged; - } - - // Define the callback method that receives location updates - @Override - public void onLocationChanged(Location location) - { - if (!location_service_running) - return; - - locationChanged = true; - mCurrentLocation = location; - - // Report to the UI that the location was updated - String msg = "Updated Location: " + location.getLatitude() + ", " + location.getLongitude(); - Log.i("RetroArch GPS", msg); - //Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); - } - - @Override - public void onPause() - { - // Save the current setting for updates - SharedPreferences prefs = UserPreferences.getPreferences(this); - SharedPreferences.Editor edit = prefs.edit(); - edit.putBoolean("LOCATION_UPDATES_ON", mUpdatesRequested); - edit.apply(); - - super.onPause(); - } - - @Override - public void onResume() - { - SharedPreferences prefs = UserPreferences.getPreferences(this); - SharedPreferences.Editor edit = prefs.edit(); - - /* - * Get any previous setting for location updates - * Gets "false" if an error occurs - */ - if (prefs.contains("LOCATION_UPDATES_ON")) - { - mUpdatesRequested = prefs.getBoolean("LOCATION_UPDATES_ON", false); - if (mUpdatesRequested) - location_service_running = true; - } - else // Otherwise, turn off location updates - { - edit.putBoolean("LOCATION_UPDATES_ON", false); - edit.apply(); - location_service_running = false; - } - - super.onResume(); - } - - @Override - public void onStop() - { - onLocationStop(); - super.onStop(); - } -} diff --git a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityPast.java b/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityPast.java deleted file mode 100644 index 4c11369ee9..0000000000 --- a/pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityPast.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.retroarch.browser.retroactivity; - -// For Android 2.3.x - -public final class RetroActivityPast extends RetroActivityCommon -{ -} From ae0d9fd60d431759d3cae09c9d730cce8f6d83f4 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 17 Aug 2018 17:42:14 +0200 Subject: [PATCH 062/182] (Wayland) Buildfixes --- gfx/drivers_context/wayland_ctx.c | 20 ++++++++++++-------- input/drivers/wayland_input.c | 19 +++++++++---------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/gfx/drivers_context/wayland_ctx.c b/gfx/drivers_context/wayland_ctx.c index 7778e6c280..cbd5418a7a 100644 --- a/gfx/drivers_context/wayland_ctx.c +++ b/gfx/drivers_context/wayland_ctx.c @@ -107,6 +107,7 @@ typedef struct gfx_ctx_wayland_data #endif } gfx_ctx_wayland_data_t; + static enum gfx_ctx_api wl_api = GFX_CTX_NONE; #ifndef EGL_OPENGL_ES3_BIT_KHR @@ -354,9 +355,10 @@ static void touch_handle_down(void *data, { int i; gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + if (num_active_touches < MAX_TOUCHES) { - for (i=0; icursor.default_cursor = wl_cursor_theme_get_cursor(wl->cursor.theme, "left_ptr"); num_active_touches = 0; - for (i=0;itouches[id].active = true; - } else - { wl->touches[id].active = false; - } - wl->touches[id].x = touch_x; - wl->touches[id].y = touch_y; + wl->touches[id].x = touch_x; + wl->touches[id].y = touch_y; } } From 566d0fc0d947a24e3ac3238842d3ffdbda1231b6 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 17 Aug 2018 17:43:28 +0200 Subject: [PATCH 063/182] Remove this --- config.features.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/config.features.h b/config.features.h index a9175e74f9..f05836d122 100644 --- a/config.features.h +++ b/config.features.h @@ -356,8 +356,6 @@ static const bool _avfoundation_supp = false; #else #define GLOBAL_CONFIG_DIR "/etc" #endif -#else -#define GLOBAL_CONFIG_DIR "" #endif #endif From 819e930b89b89243b4e4f45854d37632364813c0 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Fri, 17 Aug 2018 11:57:41 -0400 Subject: [PATCH 064/182] Qt: move drag&drop context menu into FileDropWidget source --- ui/drivers/qt/filedropwidget.cpp | 109 +++++++++++++++++++++++++++++++ ui/drivers/qt/ui_qt_window.cpp | 99 ---------------------------- 2 files changed, 109 insertions(+), 99 deletions(-) diff --git a/ui/drivers/qt/filedropwidget.cpp b/ui/drivers/qt/filedropwidget.cpp index 09eaf0abed..0d3809b668 100644 --- a/ui/drivers/qt/filedropwidget.cpp +++ b/ui/drivers/qt/filedropwidget.cpp @@ -6,7 +6,18 @@ #include #include #include +#include +#include +#include +#include + #include "filedropwidget.h" +#include "playlistentrydialog.h" +#include "../ui_qt.h" + +extern "C" { +#include "../../../file_path_special.h" +} FileDropWidget::FileDropWidget(QWidget *parent) : QWidget(parent) @@ -67,3 +78,101 @@ void FileDropWidget::dropEvent(QDropEvent *event) } } +void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) +{ + QScopedPointer menu; + QScopedPointer addEntryAction; + QScopedPointer addFilesAction; + QScopedPointer addFolderAction; + QScopedPointer editAction; + QScopedPointer deleteAction; + QPointer selectedAction; + QPoint cursorPos = QCursor::pos(); + QHash contentHash = getCurrentContentHash(); + + menu.reset(new QMenu(this)); + + addEntryAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_ENTRY)), this)); + addFilesAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_FILES)), this)); + addFolderAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_FOLDER)), this)); + editAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_EDIT)), this)); + deleteAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DELETE)), this)); + + menu->addAction(addEntryAction.data()); + menu->addAction(addFilesAction.data()); + menu->addAction(addFolderAction.data()); + + if (!contentHash.isEmpty()) + { + menu->addAction(editAction.data()); + menu->addAction(deleteAction.data()); + } + + selectedAction = menu->exec(cursorPos); + + if (!selectedAction) + return; + + if (selectedAction == addFilesAction.data()) + { + QStringList filePaths = QFileDialog::getOpenFileNames(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_FILES)); + + if (!filePaths.isEmpty()) + addFilesToPlaylist(filePaths); + } + else if (selectedAction == addEntryAction.data()) + { + addFilesToPlaylist(QStringList()); + } + else if (selectedAction == addFolderAction.data()) + { + QString dirPath = QFileDialog::getExistingDirectory(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_FOLDER), QString(), QFileDialog::ShowDirsOnly); + + if (!dirPath.isEmpty()) + addFilesToPlaylist(QStringList() << dirPath); + } + else if (selectedAction == editAction.data()) + { + PlaylistEntryDialog *playlistDialog = playlistEntryDialog(); + QHash selectedCore; + QString selectedDatabase; + QString selectedName; + QString selectedPath; + QString currentPlaylistPath = getCurrentPlaylistPath(); + + if (!playlistDialog->showDialog(contentHash)) + return; + + selectedName = m_playlistEntryDialog->getSelectedName(); + selectedPath = m_playlistEntryDialog->getSelectedPath(); + selectedCore = m_playlistEntryDialog->getSelectedCore(); + selectedDatabase = m_playlistEntryDialog->getSelectedDatabase(); + + if (selectedCore.isEmpty()) + { + selectedCore["core_name"] = "DETECT"; + selectedCore["core_path"] = "DETECT"; + } + + if (selectedDatabase.isEmpty()) + { + selectedDatabase = QFileInfo(currentPlaylistPath).fileName().remove(file_path_str(FILE_PATH_LPL_EXTENSION)); + } + + contentHash["label"] = selectedName; + contentHash["path"] = selectedPath; + contentHash["core_name"] = selectedCore.value("core_name"); + contentHash["core_path"] = selectedCore.value("core_path"); + contentHash["db_name"] = selectedDatabase; + + if (!updateCurrentPlaylistEntry(contentHash)) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + return; + } + } + else if (selectedAction == deleteAction.data()) + { + deleteCurrentPlaylistItem(); + } +} diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index d36d27dfd7..70ae24ee7a 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -1140,105 +1140,6 @@ bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowM return true; } -void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) -{ - QScopedPointer menu; - QScopedPointer addEntryAction; - QScopedPointer addFilesAction; - QScopedPointer addFolderAction; - QScopedPointer editAction; - QScopedPointer deleteAction; - QPointer selectedAction; - QPoint cursorPos = QCursor::pos(); - QHash contentHash = getCurrentContentHash(); - - menu.reset(new QMenu(this)); - - addEntryAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_ENTRY)), this)); - addFilesAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_FILES)), this)); - addFolderAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_FOLDER)), this)); - editAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_EDIT)), this)); - deleteAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DELETE)), this)); - - menu->addAction(addEntryAction.data()); - menu->addAction(addFilesAction.data()); - menu->addAction(addFolderAction.data()); - - if (!contentHash.isEmpty()) - { - menu->addAction(editAction.data()); - menu->addAction(deleteAction.data()); - } - - selectedAction = menu->exec(cursorPos); - - if (!selectedAction) - return; - - if (selectedAction == addFilesAction.data()) - { - QStringList filePaths = QFileDialog::getOpenFileNames(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_FILES)); - - if (!filePaths.isEmpty()) - addFilesToPlaylist(filePaths); - } - else if (selectedAction == addEntryAction.data()) - { - addFilesToPlaylist(QStringList()); - } - else if (selectedAction == addFolderAction.data()) - { - QString dirPath = QFileDialog::getExistingDirectory(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_FOLDER), QString(), QFileDialog::ShowDirsOnly); - - if (!dirPath.isEmpty()) - addFilesToPlaylist(QStringList() << dirPath); - } - else if (selectedAction == editAction.data()) - { - PlaylistEntryDialog *playlistDialog = playlistEntryDialog(); - QHash selectedCore; - QString selectedDatabase; - QString selectedName; - QString selectedPath; - QString currentPlaylistPath = getCurrentPlaylistPath(); - - if (!playlistDialog->showDialog(contentHash)) - return; - - selectedName = m_playlistEntryDialog->getSelectedName(); - selectedPath = m_playlistEntryDialog->getSelectedPath(); - selectedCore = m_playlistEntryDialog->getSelectedCore(); - selectedDatabase = m_playlistEntryDialog->getSelectedDatabase(); - - if (selectedCore.isEmpty()) - { - selectedCore["core_name"] = "DETECT"; - selectedCore["core_path"] = "DETECT"; - } - - if (selectedDatabase.isEmpty()) - { - selectedDatabase = QFileInfo(currentPlaylistPath).fileName().remove(file_path_str(FILE_PATH_LPL_EXTENSION)); - } - - contentHash["label"] = selectedName; - contentHash["path"] = selectedPath; - contentHash["core_name"] = selectedCore.value("core_name"); - contentHash["core_path"] = selectedCore.value("core_path"); - contentHash["db_name"] = selectedDatabase; - - if (!updateCurrentPlaylistEntry(contentHash)) - { - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - return; - } - } - else if (selectedAction == deleteAction.data()) - { - deleteCurrentPlaylistItem(); - } -} - void MainWindow::onFileBrowserTreeContextMenuRequested(const QPoint&) { #ifdef HAVE_LIBRETRODB From b76f3abfbc696dc179b1ad4e0e3e524eb2658045 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Fri, 17 Aug 2018 20:38:56 -0400 Subject: [PATCH 065/182] android: use current package name for external storage --- .../src/com/retroarch/browser/mainmenu/MainMenuActivity.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java b/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java index 88d25d6ee8..3861fea250 100644 --- a/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java +++ b/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java @@ -30,6 +30,7 @@ import android.util.Log; public final class MainMenuActivity extends PreferenceActivity { final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124; + public static String PACKAGE_NAME; boolean checkPermissions = false; public void showMessageOKCancel(String message, DialogInterface.OnClickListener onClickListener) @@ -181,7 +182,7 @@ public final class MainMenuActivity extends PreferenceActivity retro.putExtra("SDCARD", Environment.getExternalStorageDirectory().getAbsolutePath()); retro.putExtra("DOWNLOADS", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()); retro.putExtra("SCREENSHOTS", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()); - String external = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/com.retroarch/files"; + String external = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + PACKAGE_NAME + "/files"; retro.putExtra("EXTERNAL", external); } @@ -190,6 +191,8 @@ public final class MainMenuActivity extends PreferenceActivity { super.onCreate(savedInstanceState); + PACKAGE_NAME = getPackageName(); + // Bind audio stream to hardware controls. setVolumeControlStream(AudioManager.STREAM_MUSIC); From 16459bfa917a4077e727345a9c8aa080db74b68d Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 00:33:52 -0400 Subject: [PATCH 066/182] Qt: add filter/scale to shader window --- gfx/video_shader_parse.c | 7 +- ui/drivers/qt/playlist.cpp | 4 +- ui/drivers/qt/shaderparamsdialog.cpp | 636 ++++++++++++++++++++++++++- ui/drivers/qt/shaderparamsdialog.h | 19 + ui/drivers/qt/ui_qt_window.cpp | 321 +------------- ui/drivers/ui_qt.cpp | 22 +- ui/drivers/ui_qt.h | 5 - 7 files changed, 674 insertions(+), 340 deletions(-) diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index 005a9d64fb..a70d539c1f 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -503,8 +503,8 @@ bool video_shader_resolve_parameters(config_file_t *conf, char *line = NULL; const char *path = shader->pass[i].source.path; - if (string_is_empty(path)) - continue; + if (string_is_empty(path)) + continue; #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) /* First try to use the more robust slang @@ -529,6 +529,9 @@ bool video_shader_resolve_parameters(config_file_t *conf, line = (char*)malloc(4096 * sizeof(char)); line[0] = '\0'; + /* even though the pass is set in the loop too, not all passes have parameters */ + param->pass = i; + while (shader->num_parameters < ARRAY_SIZE(shader->parameters) && intfstream_gets(file, line, line_size)) { diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp index 2f9271a0bf..ef788d2c37 100644 --- a/ui/drivers/qt/playlist.cpp +++ b/ui/drivers/qt/playlist.cpp @@ -559,7 +559,7 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) strlcpy(settings->arrays.playlist_cores, new_playlist_cores, sizeof(settings->arrays.playlist_cores)); } - else if (selectedAction == deletePlaylistAction.data()) + else if (selectedItem && selectedAction == deletePlaylistAction.data()) { if (currentPlaylistFile.exists()) { @@ -583,7 +583,7 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) reloadPlaylists(); } - else if (selectedAction == hideAction.data()) + else if (selectedItem && selectedAction == hideAction.data()) { int row = m_listWidget->row(selectedItem); diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 43dc6876ce..98e532c1bd 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -1,10 +1,46 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "shaderparamsdialog.h" +#include "../ui_qt.h" + +extern "C" { +#include "../../../command.h" +#ifdef HAVE_MENU +#include "../../../menu/menu_shader.h" +#endif +} ShaderParamsDialog::ShaderParamsDialog(QWidget *parent) : QDialog(parent) + ,m_layout(NULL) { + QScrollArea *scrollArea = NULL; + QWidget *widget = NULL; + + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); + setObjectName("shaderParamsDialog"); + + m_layout = new QVBoxLayout(); + + widget = new QWidget(); + widget->setLayout(m_layout); + widget->setObjectName("shaderParamsWidget"); + scrollArea = new QScrollArea(this); + scrollArea->setWidgetResizable(true); + scrollArea->setWidget(widget); + scrollArea->setObjectName("shaderParamsScrollArea"); + + setProperty("scrollArea", QVariant::fromValue(scrollArea)); } ShaderParamsDialog::~ShaderParamsDialog() @@ -13,9 +49,20 @@ ShaderParamsDialog::~ShaderParamsDialog() void ShaderParamsDialog::resizeEvent(QResizeEvent *event) { + QVariant scrollAreaVariant = property("scrollArea"); + QScrollArea *scrollArea = NULL; + QDialog::resizeEvent(event); - emit resized(event->size()); + if (!scrollAreaVariant.isValid()) + return; + + scrollArea = scrollAreaVariant.value(); + + if (!scrollArea) + return; + + scrollArea->resize(event->size()); } void ShaderParamsDialog::closeEvent(QCloseEvent *event) @@ -25,3 +72,590 @@ void ShaderParamsDialog::closeEvent(QCloseEvent *event) emit closed(); } +QString ShaderParamsDialog::getFilterLabel(unsigned filter) +{ + QString filterString; + + switch (filter) + { + case 0: + filterString = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE); + break; + case 1: + filterString = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LINEAR); + break; + case 2: + filterString = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NEAREST); + break; + default: + break; + } + + return filterString; +} + +void ShaderParamsDialog::clearLayout(QLayout *layout) +{ + QLayoutItem *child = NULL; + + while (layout->count() && ((child = layout->takeAt(0)) != 0)) + { + QWidget *widget = child->widget(); + QLayout *childLayout = child->layout(); + + if (widget) + { + QLayout *widgetLayout = widget->layout(); + + if (widgetLayout) + clearLayout(widgetLayout); + + /* deleteLater() doesn't work right for some reason here, + * so just disconnect any signals in case there are pending events, + * and delete the widget immediately. + */ + widget->disconnect(); + delete widget; + } + + if (childLayout) + clearLayout(childLayout); + + delete child; + } +} + +void ShaderParamsDialog::getShaders(struct video_shader **menu_shader, struct video_shader **video_shader) +{ + video_shader_ctx_t shader_info = {0}; +#ifdef HAVE_MENU + struct video_shader *shader = menu_shader_get(); + + if (menu_shader) + { + if (shader) + { + *menu_shader = shader; + } + else + { + *menu_shader = NULL; + } + } + + if (video_shader) + { + if (shader) + { + *video_shader = shader_info.data; + } + else + { + *video_shader = NULL; + } + } +#endif + + if (video_shader) + { + if (!video_shader_driver_get_current_shader(&shader_info)) + { + *video_shader = NULL; + return; + } + + if (!shader_info.data || shader_info.data->num_parameters > GFX_MAX_PARAMETERS) + { + *video_shader = NULL; + return; + } + + if (shader_info.data) + { + *video_shader = shader_info.data; + } + else + { + *video_shader = NULL; + } + } +} + +void ShaderParamsDialog::onFilterComboBoxIndexChanged(int) +{ + QComboBox *comboBox = qobject_cast(sender()); + QVariant passVariant; + int pass = 0; + bool ok = false; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + + getShaders(&menu_shader, &video_shader); + + if (!comboBox) + return; + + passVariant = comboBox->property("pass"); + + if (!passVariant.isValid()) + return; + + pass = passVariant.toInt(&ok); + + if (!ok) + return; + + if (menu_shader && pass >= 0 && pass < static_cast(menu_shader->passes)) + { + QVariant data = comboBox->currentData(); + + if (data.isValid()) + { + unsigned filter = data.toUInt(&ok); + + if (ok) + { + if (menu_shader) + menu_shader->pass[pass].filter = filter; + if (video_shader) + video_shader->pass[pass].filter = filter; + + command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); + } + } + } +} + +void ShaderParamsDialog::onScaleComboBoxIndexChanged(int) +{ + QComboBox *comboBox = qobject_cast(sender()); + QVariant passVariant; + int pass = 0; + bool ok = false; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + + getShaders(&menu_shader, &video_shader); + + if (!comboBox) + return; + + passVariant = comboBox->property("pass"); + + if (!passVariant.isValid()) + return; + + pass = passVariant.toInt(&ok); + + if (!ok) + return; + + if (menu_shader && pass >= 0 && pass < static_cast(menu_shader->passes)) + { + QVariant data = comboBox->currentData(); + + if (data.isValid()) + { + unsigned scale = data.toUInt(&ok); + + if (ok) + { + if (menu_shader) + { + menu_shader->pass[pass].fbo.scale_x = scale; + menu_shader->pass[pass].fbo.scale_y = scale; + menu_shader->pass[pass].fbo.valid = scale; + } + + if (video_shader) + { + video_shader->pass[pass].fbo.scale_x = scale; + video_shader->pass[pass].fbo.scale_y = scale; + video_shader->pass[pass].fbo.valid = scale; + } + + command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); + } + } + } +} + +void ShaderParamsDialog::reload() +{ + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + int i; + unsigned j; + + getShaders(&menu_shader, &video_shader); + + /* NOTE: For some reason, menu_shader_get() returns a COPY of what get_current_shader() gives us. + * And if you want to be able to change shader settings/parameters from both the raster menu and + * Qt at the same time... you must change BOTH or one will overwrite the other. + */ + + if ((video_shader && video_shader->passes == 0) || !video_shader) + goto end; + + clearLayout(m_layout); + + /* NOTE: We assume that parameters are always grouped in order by the pass number, e.g., all parameters for pass 0 come first, then params for pass 1, etc. */ + for (i = 0; i < static_cast(video_shader->passes); i++) + { + QFormLayout *form = NULL; + QGroupBox *groupBox = NULL; + QFileInfo fileInfo(video_shader->pass[i].source.path); + QString shaderBasename = fileInfo.completeBaseName(); + QHBoxLayout *filterScaleHBoxLayout = NULL; + QComboBox *filterComboBox = new QComboBox(); + QComboBox *scaleComboBox = new QComboBox(); + unsigned j = 0; + + filterComboBox->setProperty("pass", i); + scaleComboBox->setProperty("pass", i); + + for (;;) + { + QString filterLabel = getFilterLabel(j); + + if (filterLabel.isEmpty()) + break; + + if (j == 0) + filterLabel = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE); + + filterComboBox->addItem(filterLabel, j); + + j++; + } + + for (j = 0; j < 7; j++) + { + QString label; + + if (j == 0) + label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE); + else + label = QString::number(j) + "x"; + + scaleComboBox->addItem(label, j); + } + + filterComboBox->setCurrentIndex(static_cast(video_shader->pass[i].filter)); + scaleComboBox->setCurrentIndex(static_cast(video_shader->pass[i].fbo.scale_x)); + + /* connect the signals only after the initial index is set */ + connect(filterComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onFilterComboBoxIndexChanged(int))); + connect(scaleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onScaleComboBoxIndexChanged(int))); + + form = new QFormLayout(); + groupBox = new QGroupBox(shaderBasename); + groupBox->setLayout(form); + + m_layout->addWidget(groupBox); + + filterScaleHBoxLayout = new QHBoxLayout(); + filterScaleHBoxLayout->addWidget(new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FILTER))); + filterScaleHBoxLayout->addWidget(filterComboBox); + filterScaleHBoxLayout->addWidget(new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCALE))); + filterScaleHBoxLayout->addWidget(scaleComboBox); + + form->addRow("", filterScaleHBoxLayout); + + for (j = 0; j < video_shader->num_parameters; j++) + { + struct video_shader_parameter *param = &video_shader->parameters[j]; + + if (param->pass != i) + continue; + + addShaderParam(param, j, form); + } + } + + m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); + +end: + resize(720, 480); + show(); +} + +void ShaderParamsDialog::addShaderParam(struct video_shader_parameter *param, int parameter, QFormLayout *form) +{ + QString desc = param->desc; + + if ((param->minimum == 0.0) + && (param->maximum + == (param->minimum + + param->step))) + { + /* option is basically a bool, so use a checkbox */ + QCheckBox *checkBox = new QCheckBox(this); + checkBox->setChecked(param->current == param->maximum ? true : false); + checkBox->setProperty("pass", param->pass); + + connect(checkBox, SIGNAL(clicked()), this, SLOT(onShaderParamCheckBoxClicked())); + + form->addRow(desc, checkBox); + } + else + { + QDoubleSpinBox *doubleSpinBox = NULL; + QSpinBox *spinBox = NULL; + QHBoxLayout *box = new QHBoxLayout(); + QSlider *slider = new QSlider(Qt::Horizontal, this); + double value = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); + double intpart = 0; + bool stepIsFractional = modf(param->step, &intpart); + + slider->setRange(0, 100); + slider->setSingleStep(1); + slider->setValue(value); + slider->setProperty("param", parameter); + + connect(slider, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSliderValueChanged(int))); + + box->addWidget(slider); + + if (stepIsFractional) + { + doubleSpinBox = new QDoubleSpinBox(this); + doubleSpinBox->setRange(param->minimum, param->maximum); + doubleSpinBox->setSingleStep(param->step); + doubleSpinBox->setValue(param->current); + doubleSpinBox->setProperty("slider", QVariant::fromValue(slider)); + slider->setProperty("doubleSpinBox", QVariant::fromValue(doubleSpinBox)); + + connect(doubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onShaderParamDoubleSpinBoxValueChanged(double))); + + box->addWidget(doubleSpinBox); + } + else + { + spinBox = new QSpinBox(this); + spinBox->setRange(param->minimum, param->maximum); + spinBox->setSingleStep(param->step); + spinBox->setValue(param->current); + spinBox->setProperty("slider", QVariant::fromValue(slider)); + slider->setProperty("spinBox", QVariant::fromValue(spinBox)); + + connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSpinBoxValueChanged(int))); + + box->addWidget(spinBox); + } + + form->addRow(desc, box); + } +} + +void ShaderParamsDialog::onShaderParamCheckBoxClicked() +{ + QCheckBox *checkBox = qobject_cast(sender()); + QVariant paramVariant; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + + getShaders(&menu_shader, &video_shader); + + if (!checkBox) + return; + + if (menu_shader && menu_shader->passes == 0) + return; + + paramVariant = checkBox->property("parameter"); + + if (paramVariant.isValid()) + { + bool ok = false; + int parameter = paramVariant.toInt(&ok); + + if (!ok) + return; + + if (menu_shader) + { + struct video_shader_parameter *param = NULL; + + param = &menu_shader->parameters[parameter]; + + if (param) + param->current = (checkBox->isChecked() ? param->maximum : param->minimum); + } + + if (video_shader) + { + struct video_shader_parameter *param = NULL; + + param = &video_shader->parameters[parameter]; + + if (param) + param->current = (checkBox->isChecked() ? param->maximum : param->minimum); + } + } +} + +void ShaderParamsDialog::onShaderParamSliderValueChanged(int) +{ + QVariant spinBoxVariant; + QVariant paramVariant; + QSlider *slider = qobject_cast(sender()); + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + double newValue = 0.0; + + getShaders(&menu_shader, &video_shader); + + if (!slider) + return; + + spinBoxVariant = slider->property("spinBox"); + paramVariant = slider->property("param"); + + if (paramVariant.isValid()) + { + bool ok = false; + int parameter = paramVariant.toInt(&ok); + + if (ok) + { + if (menu_shader) + { + struct video_shader_parameter *param = &menu_shader->parameters[parameter]; + + newValue = MainWindow::lerp(0, 100, param->minimum, param->maximum, slider->value()); + param->current = newValue; + } + + if (video_shader) + { + struct video_shader_parameter *param = &video_shader->parameters[parameter]; + + newValue = MainWindow::lerp(0, 100, param->minimum, param->maximum, slider->value()); + param->current = newValue; + } + } + } + + if (spinBoxVariant.isValid()) + { + QSpinBox *spinBox = spinBoxVariant.value(); + + if (!spinBox) + return; + + spinBox->blockSignals(true); + spinBox->setValue(newValue); + spinBox->blockSignals(false); + } + else + { + QVariant doubleSpinBoxVariant = slider->property("doubleSpinBox"); + QDoubleSpinBox *doubleSpinBox = doubleSpinBoxVariant.value(); + + if (!doubleSpinBox) + return; + + doubleSpinBox->blockSignals(true); + doubleSpinBox->setValue(newValue); + doubleSpinBox->blockSignals(false); + } +} + +void ShaderParamsDialog::onShaderParamSpinBoxValueChanged(int value) +{ + QSpinBox *spinBox = qobject_cast(sender()); + QVariant sliderVariant; + QVariant paramVariant; + QSlider *slider = NULL; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + double newValue = 0.0; + + getShaders(&menu_shader, &video_shader); + + if (!spinBox) + return; + + sliderVariant = spinBox->property("slider"); + + if (!sliderVariant.isValid()) + return; + + slider = sliderVariant.value(); + + if (!slider) + return; + + paramVariant = slider->property("param"); + + if (paramVariant.isValid()) + { + bool ok = false; + int parameter = paramVariant.toInt(&ok); + + if (ok) + { + if (menu_shader) + { + struct video_shader_parameter *param = &menu_shader->parameters[parameter]; + + param->current = value; + newValue = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); + slider->blockSignals(true); + slider->setValue(newValue); + slider->blockSignals(false); + } + + if (video_shader) + { + struct video_shader_parameter *param = &video_shader->parameters[parameter]; + + param->current = value; + newValue = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); + slider->blockSignals(true); + slider->setValue(newValue); + slider->blockSignals(false); + } + } + } +} + +void ShaderParamsDialog::onShaderParamDoubleSpinBoxValueChanged(double value) +{ + QDoubleSpinBox *doubleSpinBox = qobject_cast(sender()); + QVariant sliderVariant; + QVariant paramVariant; + QSlider *slider = NULL; + struct video_shader_parameter *param = NULL; + double newValue = 0.0; + + if (!doubleSpinBox) + return; + + sliderVariant = doubleSpinBox->property("slider"); + + if (!sliderVariant.isValid()) + return; + + slider = sliderVariant.value(); + + if (!slider) + return; + + paramVariant = slider->property("param"); + + if (paramVariant.isValid()) + { + param = paramVariant.value(); + + if (param) + { + param->current = value; + newValue = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); + slider->blockSignals(true); + slider->setValue(newValue); + slider->blockSignals(false); + } + } +} diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h index f2b98a8118..5fb5376862 100644 --- a/ui/drivers/qt/shaderparamsdialog.h +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -5,6 +5,9 @@ class QCloseEvent; class QResizeEvent; +class QVBoxLayout; +class QFormLayout; +class QLayout; class ShaderParamsDialog : public QDialog { @@ -15,6 +18,22 @@ public: signals: void closed(); void resized(QSize size); +public slots: + void reload(); +private slots: + void onShaderParamCheckBoxClicked(); + void onShaderParamSliderValueChanged(int value); + void onShaderParamSpinBoxValueChanged(int value); + void onShaderParamDoubleSpinBoxValueChanged(double value); + void onFilterComboBoxIndexChanged(int index); + void onScaleComboBoxIndexChanged(int index); +private: + QString getFilterLabel(unsigned filter); + void addShaderParam(struct video_shader_parameter *param, int parameter, QFormLayout *form); + void clearLayout(QLayout *layout); + void getShaders(struct video_shader **menu_shader, struct video_shader **video_shader); + + QVBoxLayout *m_layout; protected: void closeEvent(QCloseEvent *event); void resizeEvent(QResizeEvent *event); diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 70ae24ee7a..d9c25546c5 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -314,7 +314,7 @@ MainWindow::MainWindow(QWidget *parent) : ,m_allPlaylistsGridMaxCount(0) ,m_playlistEntryDialog(NULL) ,m_statusMessageElapsedTimer() - ,m_shaderParamsDialog() + ,m_shaderParamsDialog(new ShaderParamsDialog()) ,m_networkManager(new QNetworkAccessManager(this)) ,m_updateProgressDialog(new QProgressDialog()) ,m_updateFile() @@ -585,312 +585,6 @@ double MainWindow::lerp(double x, double y, double a, double b, double d) { return a + (b - a) * ((double)(d - x) / (double)(y - x)); } -void MainWindow::onShaderParamsDialogResized(QSize size) -{ - QVariant scrollAreaVariant = m_shaderParamsDialog->property("scrollArea"); - QScrollArea *scrollArea = NULL; - - if (!scrollAreaVariant.isValid()) - return; - - scrollArea = scrollAreaVariant.value(); - - if (!scrollArea) - return; - - scrollArea->resize(size); -} - -void MainWindow::onShaderParamsClicked() -{ - video_shader_ctx_t shader_info = {0}; - unsigned i; - int last_pass = -1; - QFormLayout *last_form = NULL; - QGroupBox *last_group = NULL; - QScrollArea *scrollArea = NULL; - QWidget *widget = NULL; - QVBoxLayout *layout = NULL; - - if (!video_shader_driver_get_current_shader(&shader_info)) - return; - - if (!shader_info.data || shader_info.data->num_parameters > GFX_MAX_PARAMETERS) - return; - - /* shader might have changed, so re-create the entire window */ - if (m_shaderParamsDialog) - delete m_shaderParamsDialog; - - m_shaderParamsDialog = new ShaderParamsDialog(); - m_shaderParamsDialog->setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS)); - m_shaderParamsDialog->setObjectName("shaderParamsDialog"); - - layout = new QVBoxLayout(); - widget = new QWidget(); - widget->setLayout(layout); - widget->setObjectName("shaderParamsWidget"); - scrollArea = new QScrollArea(m_shaderParamsDialog); - scrollArea->setWidgetResizable(true); - scrollArea->setWidget(widget); - scrollArea->setObjectName("shaderParamsScrollArea"); - - m_shaderParamsDialog->setProperty("scrollArea", QVariant::fromValue(scrollArea)); - - connect(m_shaderParamsDialog, SIGNAL(closed()), m_shaderParamsDialog, SLOT(deleteLater())); - connect(m_shaderParamsDialog, SIGNAL(resized(QSize)), this, SLOT(onShaderParamsDialogResized(QSize))); - - if (shader_info.data->num_parameters == 0) - { - QLabel *label = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS), m_shaderParamsDialog); - label->setAlignment(Qt::AlignCenter); - - layout->addWidget(label); - } - else - { - /* NOTE: We assume that parameters are always grouped in order by the pass number, e.g., all parameters for pass 0 come first, then params for pass 1, etc. */ - for (i = 0; i < shader_info.data->num_parameters; i++) - { - struct video_shader_parameter *param = &shader_info.data->parameters[i]; - QString desc = param->desc; - QFormLayout *form = last_form; - - if (param->pass > last_pass) - { - QGroupBox *groupBox = NULL; - QFileInfo fileInfo(shader_info.data->pass[param->pass].source.path); - QString shaderBasename = fileInfo.completeBaseName(); - - form = new QFormLayout(); - groupBox = new QGroupBox(shaderBasename); - groupBox->setLayout(form); - - layout->addWidget(groupBox); - - last_form = form; - last_pass = param->pass; - } - - if ((param->minimum == 0.0) - && (param->maximum - == (param->minimum - + param->step))) - { - /* option is basically a bool, so use a checkbox */ - QCheckBox *checkBox = new QCheckBox(m_shaderParamsDialog); - checkBox->setChecked(param->current == param->maximum ? true : false); - checkBox->setProperty("param", QVariant::fromValue(param)); - - connect(checkBox, SIGNAL(clicked()), this, SLOT(onShaderParamCheckBoxClicked())); - - form->addRow(desc, checkBox); - } - else - { - QDoubleSpinBox *doubleSpinBox = NULL; - QSpinBox *spinBox = NULL; - QHBoxLayout *box = new QHBoxLayout(); - QSlider *slider = new QSlider(Qt::Horizontal, m_shaderParamsDialog); - double value = lerp(param->minimum, param->maximum, 0, 100, param->current); - double intpart = 0; - bool stepIsFractional = modf(param->step, &intpart); - - slider->setRange(0, 100); - slider->setSingleStep(1); - slider->setValue(value); - slider->setProperty("param", QVariant::fromValue(param)); - - connect(slider, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSliderValueChanged(int))); - - box->addWidget(slider); - - if (stepIsFractional) - { - doubleSpinBox = new QDoubleSpinBox(m_shaderParamsDialog); - doubleSpinBox->setRange(param->minimum, param->maximum); - doubleSpinBox->setSingleStep(param->step); - doubleSpinBox->setValue(param->current); - doubleSpinBox->setProperty("slider", QVariant::fromValue(slider)); - slider->setProperty("doubleSpinBox", QVariant::fromValue(doubleSpinBox)); - - connect(doubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onShaderParamDoubleSpinBoxValueChanged(double))); - - box->addWidget(doubleSpinBox); - } - else - { - spinBox = new QSpinBox(m_shaderParamsDialog); - spinBox->setRange(param->minimum, param->maximum); - spinBox->setSingleStep(param->step); - spinBox->setValue(param->current); - spinBox->setProperty("slider", QVariant::fromValue(slider)); - slider->setProperty("spinBox", QVariant::fromValue(spinBox)); - - connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSpinBoxValueChanged(int))); - - box->addWidget(spinBox); - } - - form->addRow(desc, box); - } - } - - layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); - } - - m_shaderParamsDialog->resize(720, 480); - m_shaderParamsDialog->show(); -} - -void MainWindow::onShaderParamCheckBoxClicked() -{ - QCheckBox *checkBox = qobject_cast(sender()); - QVariant paramVariant; - struct video_shader_parameter *param = NULL; - - if (!checkBox) - return; - - paramVariant = checkBox->property("param"); - - if (paramVariant.isValid()) - { - param = paramVariant.value(); - - if (param) - param->current = (checkBox->isChecked() ? param->maximum : param->minimum); - } -} - -void MainWindow::onShaderParamSliderValueChanged(int value) -{ - QVariant spinBoxVariant; - QVariant paramVariant; - QSlider *slider = qobject_cast(sender()); - struct video_shader_parameter *param = NULL; - double newValue = 0.0; - - if (!slider) - return; - - spinBoxVariant = slider->property("spinBox"); - paramVariant = slider->property("param"); - - if (paramVariant.isValid()) - { - param = paramVariant.value(); - - if (param) - { - newValue = lerp(0, 100, param->minimum, param->maximum, slider->value()); - param->current = newValue; - } - } - - if (spinBoxVariant.isValid()) - { - QSpinBox *spinBox = spinBoxVariant.value(); - - if (!spinBox) - return; - - spinBox->blockSignals(true); - spinBox->setValue(newValue); - spinBox->blockSignals(false); - } - else - { - QVariant doubleSpinBoxVariant = slider->property("doubleSpinBox"); - QDoubleSpinBox *doubleSpinBox = doubleSpinBoxVariant.value(); - - if (!doubleSpinBox) - return; - - doubleSpinBox->blockSignals(true); - doubleSpinBox->setValue(newValue); - doubleSpinBox->blockSignals(false); - } -} - -void MainWindow::onShaderParamSpinBoxValueChanged(int value) -{ - QSpinBox *spinBox = qobject_cast(sender()); - QVariant sliderVariant; - QVariant paramVariant; - QSlider *slider = NULL; - struct video_shader_parameter *param = NULL; - double newValue = 0.0; - - if (!spinBox) - return; - - sliderVariant = spinBox->property("slider"); - - if (!sliderVariant.isValid()) - return; - - slider = sliderVariant.value(); - - if (!slider) - return; - - paramVariant = slider->property("param"); - - if (paramVariant.isValid()) - { - param = paramVariant.value(); - - if (param) - { - param->current = value; - newValue = lerp(param->minimum, param->maximum, 0, 100, param->current); - slider->blockSignals(true); - slider->setValue(newValue); - slider->blockSignals(false); - } - } -} - -void MainWindow::onShaderParamDoubleSpinBoxValueChanged(double value) -{ - QDoubleSpinBox *doubleSpinBox = qobject_cast(sender()); - QVariant sliderVariant; - QVariant paramVariant; - QSlider *slider = NULL; - struct video_shader_parameter *param = NULL; - double newValue = 0.0; - - if (!doubleSpinBox) - return; - - sliderVariant = doubleSpinBox->property("slider"); - - if (!sliderVariant.isValid()) - return; - - slider = sliderVariant.value(); - - if (!slider) - return; - - paramVariant = slider->property("param"); - - if (paramVariant.isValid()) - { - param = paramVariant.value(); - - if (param) - { - param->current = value; - newValue = lerp(param->minimum, param->maximum, 0, 100, param->current); - slider->blockSignals(true); - slider->setValue(newValue); - slider->blockSignals(false); - } - } -} - void MainWindow::onGridItemClicked(ThumbnailWidget *widget) { QHash hash; @@ -1225,10 +919,20 @@ void MainWindow::deferReloadShaderParams() emit gotReloadShaderParams(); } +void MainWindow::onShaderParamsClicked() +{ + if (!m_shaderParamsDialog) + return; + + m_shaderParamsDialog->show(); + + onGotReloadShaderParams(); +} + void MainWindow::onGotReloadShaderParams() { if (m_shaderParamsDialog && m_shaderParamsDialog->isVisible()) - onShaderParamsClicked(); + m_shaderParamsDialog->reload(); } void MainWindow::appendLogMessage(const QString &msg) @@ -1736,7 +1440,6 @@ void MainWindow::onTableWidgetDeletePressed() QHash MainWindow::getCurrentContentHash() { QTableWidgetItem *contentItem = m_tableWidget->currentItem(); - QListWidgetItem *playlistItem = m_listWidget->currentItem(); QHash contentHash; ViewType viewType = getCurrentViewType(); diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index 3909cb9209..067cf7b661 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -324,7 +324,7 @@ static void* ui_companion_qt_init(void) QObject::connect(viewClosedDocksMenu, SIGNAL(aboutToShow()), mainwindow, SLOT(onViewClosedDocksAboutToShow())); - viewMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_SHADER_PARAMS), mainwindow, SLOT(onShaderParamsClicked())); + viewMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS), mainwindow, SLOT(onShaderParamsClicked())); viewMenu->addSeparator(); viewMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_ICONS), mainwindow, SLOT(onIconViewClicked())); @@ -634,26 +634,6 @@ static void ui_companion_qt_event_command(void *data, enum event_command cmd) switch (cmd) { case CMD_EVENT_SHADERS_APPLY_CHANGES: - { - /* If shader was turned off, reload the params window manually because PRESET_LOADED won't be fired */ - video_shader_ctx_t shader_info = {0}; - - if (!video_shader_driver_get_current_shader(&shader_info)) - break; - - /* Isn't there a better way to do this? */ - if (shader_info.data && shader_info.data->num_parameters == 0) - { - if (shader_info.data->passes == 1 && string_is_empty(shader_info.data->pass[0].source.path)) - { - RARCH_LOG("[Qt]: Clearing shader parameters.\n"); - win_handle->qtWindow->deferReloadShaderParams(); - } - } - - /* Otherwise, PRESET_LOADED fires in more situations than APPLY_CHANGES, so use that for reloading the params window */ - break; - } case CMD_EVENT_SHADER_PRESET_LOADED: RARCH_LOG("[Qt]: Reloading shader parameters.\n"); win_handle->qtWindow->deferReloadShaderParams(); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 418e1fb441..0b8debb3b9 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -368,11 +368,6 @@ private slots: void onShowErrorMessage(QString msg); void onShowInfoMessage(QString msg); void onContributorsClicked(); - void onShaderParamCheckBoxClicked(); - void onShaderParamSliderValueChanged(int value); - void onShaderParamSpinBoxValueChanged(int value); - void onShaderParamDoubleSpinBoxValueChanged(double value); - void onShaderParamsDialogResized(QSize size); int onExtractArchive(QString path); private: From 1d4cb967f03b950a6da63fb7d4266427a6841894 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 00:48:40 -0400 Subject: [PATCH 067/182] fix scan-build error "branch condition evaluates to garbage" --- configuration.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configuration.c b/configuration.c index 868dc5ab7b..b273a4f246 100644 --- a/configuration.c +++ b/configuration.c @@ -1069,7 +1069,7 @@ bool config_overlay_enable_default(void) static struct config_array_setting *populate_settings_array(settings_t *settings, int *size) { unsigned count = 0; - struct config_array_setting *tmp = (struct config_array_setting*)malloc((*size + 1) * sizeof(struct config_array_setting)); + struct config_array_setting *tmp = (struct config_array_setting*)calloc(1, (*size + 1) * sizeof(struct config_array_setting)); /* Arrays */ SETTING_ARRAY("playlist_names", settings->arrays.playlist_names, false, NULL, true); @@ -1308,7 +1308,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("video_vsync", &settings->bools.video_vsync, true, vsync, false); SETTING_BOOL("video_hard_sync", &settings->bools.video_hard_sync, true, hard_sync, false); SETTING_BOOL("video_black_frame_insertion", &settings->bools.video_black_frame_insertion, true, black_frame_insertion, false); - SETTING_BOOL("crt_switch_resolution", &settings->bools.crt_switch_resolution, true, crt_switch_resolution, false); + SETTING_BOOL("crt_switch_resolution", &settings->bools.crt_switch_resolution, true, crt_switch_resolution, false); SETTING_BOOL("video_disable_composition", &settings->bools.video_disable_composition, true, disable_composition, false); SETTING_BOOL("pause_nonactive", &settings->bools.pause_nonactive, true, pause_nonactive, false); SETTING_BOOL("video_gpu_screenshot", &settings->bools.video_gpu_screenshot, true, gpu_screenshot, false); @@ -4431,7 +4431,7 @@ bool config_save_overrides(int override_type) for (i = 0; i < (unsigned)path_settings_size; i++) { - /* blacklist video_shader, better handled by shader presets*/ + /* blacklist video_shader, better handled by shader presets*/ /* to-do: add setting to control blacklisting */ if (string_is_equal(path_settings[i].ident, "video_shader")) continue; From fbe08aa0c5377afaafe55da9ff445ff4f64c22d0 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 00:51:07 -0400 Subject: [PATCH 068/182] fix double free --- libretro-common/formats/png/rpng.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libretro-common/formats/png/rpng.c b/libretro-common/formats/png/rpng.c index e28272124c..1bf075759d 100644 --- a/libretro-common/formats/png/rpng.c +++ b/libretro-common/formats/png/rpng.c @@ -544,6 +544,7 @@ static int png_reverse_filter_init(const struct png_ihdr *ihdr, if (pngp->pass_size > pngp->total_out) { free(pngp->data); + pngp->data = NULL; return -1; } @@ -721,6 +722,7 @@ static int png_reverse_filter_adam7_iterate(uint32_t **data_, free(pngp->data); + pngp->data = NULL; pngp->pass_width = 0; pngp->pass_height = 0; pngp->pass_size = 0; @@ -746,7 +748,10 @@ static int png_reverse_filter_adam7(uint32_t **data_, return 0; case IMAGE_PROCESS_ERROR: if (pngp->data) + { free(pngp->data); + pngp->data = NULL; + } pngp->inflate_buf -= pngp->adam7_restore_buf_size; pngp->adam7_restore_buf_size = 0; return -1; From 23d7fbcaf37155ae1193c01ae623e42b51565e7f Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 00:56:10 -0400 Subject: [PATCH 069/182] fix memory leaks --- configuration.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configuration.c b/configuration.c index b273a4f246..af8979c63f 100644 --- a/configuration.c +++ b/configuration.c @@ -1112,7 +1112,7 @@ static struct config_path_setting *populate_settings_path(settings_t *settings, { unsigned count = 0; global_t *global = global_get_ptr(); - struct config_path_setting *tmp = (struct config_path_setting*)malloc((*size + 1) * sizeof(struct config_path_setting)); + struct config_path_setting *tmp = (struct config_path_setting*)calloc(1, (*size + 1) * sizeof(struct config_path_setting)); /* Paths */ #ifdef HAVE_XMB @@ -3027,6 +3027,8 @@ end: free(array_settings); if (path_settings) free(path_settings); + if (size_settings) + free(size_settings); free(tmp_str); return ret; } @@ -4536,6 +4538,8 @@ bool config_save_overrides(int override_type) free(path_settings); if (path_overrides) free(path_overrides); + if (size_overrides) + free(size_overrides); free(settings); free(config_directory); free(override_directory); From 2f87f669f103cc3148d78e361ed275d5c474b8dd Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 01:00:40 -0400 Subject: [PATCH 070/182] fix null dereference (but scan-build still warns with "Assigned value is garbage or undefined") --- libretro-common/formats/jpeg/rjpeg.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/libretro-common/formats/jpeg/rjpeg.c b/libretro-common/formats/jpeg/rjpeg.c index 9ef95e4f08..65cb6c3966 100644 --- a/libretro-common/formats/jpeg/rjpeg.c +++ b/libretro-common/formats/jpeg/rjpeg.c @@ -2505,15 +2505,18 @@ static uint8_t *rjpeg_load_jpeg_image(rjpeg__jpeg *z, if (n >= 3) { uint8_t *y = coutput[0]; - if (z->s->img_n == 3) - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - else - for (i=0; i < z->s->img_x; ++i) - { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; /* not used if n==3 */ - out += n; - } + if (y) + { + if (z->s->img_n == 3) + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + else + for (i=0; i < z->s->img_x; ++i) + { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; /* not used if n==3 */ + out += n; + } + } } else { From 077ef86bab19d2fa5072ad01d4644ee17ae7b5f2 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 01:07:51 -0400 Subject: [PATCH 071/182] fix null pointer dereferences --- tasks/task_content.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tasks/task_content.c b/tasks/task_content.c index 4ca0f0ba67..d8581b03de 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -1772,10 +1772,13 @@ void content_set_subsystem(unsigned idx) pending_subsystem_id = idx; - strlcpy(pending_subsystem_ident, - subsystem->ident, sizeof(pending_subsystem_ident)); + if (subsystem) + { + strlcpy(pending_subsystem_ident, + subsystem->ident, sizeof(pending_subsystem_ident)); - pending_subsystem_rom_num = subsystem->num_roms; + pending_subsystem_rom_num = subsystem->num_roms; + } RARCH_LOG("[subsystem] settings current subsytem to: %d(%s) roms: %d\n", pending_subsystem_id, pending_subsystem_ident, pending_subsystem_rom_num); From c59cbfc4e886818480eead449e545529d6577ae2 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 01:07:57 -0400 Subject: [PATCH 072/182] fix memory leaks --- tasks/task_content.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tasks/task_content.c b/tasks/task_content.c index d8581b03de..85bb9fc13d 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -1569,6 +1569,10 @@ end: free(content_ctx.name_ups); if (content_ctx.directory_system) free(content_ctx.directory_system); + if (content_ctx.directory_cache) + free(content_ctx.directory_cache); + if (content_ctx.valid_extensions) + free(content_ctx.valid_extensions); if (!ret) { From dfd85125ad13c9c84ee89eb9872b0b6af0ee0eea Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 01:10:05 -0400 Subject: [PATCH 073/182] fix null deref --- command.c | 2 +- menu/drivers/materialui.c | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/command.c b/command.c index 837929f506..55b2cf94e6 100644 --- a/command.c +++ b/command.c @@ -1066,7 +1066,7 @@ static void command_event_init_controllers(void) break; } - if (set_controller && i < info->ports.size) + if (set_controller && info && i < info->ports.size) { pad.device = device; pad.port = i; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 3c34362b30..0c80afa196 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -543,17 +543,20 @@ static void materialui_render_messagebox(materialui_handle_t *mui, } } - menu_display_set_alpha(body_bg_color, 1.0); + if (body_bg_color) + { + menu_display_set_alpha(body_bg_color, 1.0); - menu_display_draw_quad( - video_info, - x - longest_width / 2.0 - mui->margin * 2.0, - y - line_height / 2.0 - mui->margin * 2.0, - longest_width + mui->margin * 4.0, - line_height * list->size + mui->margin * 4.0, - width, - height, - &body_bg_color[0]); + menu_display_draw_quad( + video_info, + x - longest_width / 2.0 - mui->margin * 2.0, + y - line_height / 2.0 - mui->margin * 2.0, + longest_width + mui->margin * 4.0, + line_height * list->size + mui->margin * 4.0, + width, + height, + &body_bg_color[0]); + } /* print each line */ for (i = 0; i < list->size; i++) From 849792dc2cb6842fdfbba5bcfe73144ca440e821 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 01:15:50 -0400 Subject: [PATCH 074/182] fix memory leaks --- database_info.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/database_info.c b/database_info.c index 894ae250ac..96da1c48a9 100644 --- a/database_info.c +++ b/database_info.c @@ -478,6 +478,36 @@ database_info_list_t *database_info_list_new( if (!new_ptr) { + if (db_info.bbfc_rating) + free(db_info.bbfc_rating); + if (db_info.cero_rating) + free(db_info.cero_rating); + if (db_info.description) + free(db_info.description); + if (db_info.edge_magazine_review) + free(db_info.edge_magazine_review); + if (db_info.elspa_rating) + free(db_info.elspa_rating); + if (db_info.enhancement_hw) + free(db_info.enhancement_hw); + if (db_info.esrb_rating) + free(db_info.esrb_rating); + if (db_info.franchise) + free(db_info.franchise); + if (db_info.genre) + free(db_info.genre); + if (db_info.name) + free(db_info.name); + if (db_info.origin) + free(db_info.origin); + if (db_info.pegi_rating) + free(db_info.pegi_rating); + if (db_info.publisher) + free(db_info.publisher); + if (db_info.rom_name) + free(db_info.rom_name); + if (db_info.serial) + free(db_info.serial); database_info_list_free(database_info_list); free(database_info); free(database_info_list); From a0cf6b6b5e5aedac3b39fb10381e26a3f4d09918 Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Sat, 18 Aug 2018 02:12:51 -0500 Subject: [PATCH 075/182] discord: added additional discord events and other improvements --- command.c | 7 +++ discord/discord.c | 114 ++++++++++++++++++++++++++++++++++-------- discord/discord.h | 1 + intl/msg_hash_ar.h | 12 ++++- intl/msg_hash_chs.h | 12 ++++- intl/msg_hash_cht.h | 12 ++++- intl/msg_hash_de.h | 12 ++++- intl/msg_hash_eo.h | 12 ++++- intl/msg_hash_es.h | 16 ++++++ intl/msg_hash_fr.h | 12 ++++- intl/msg_hash_it.h | 12 ++++- intl/msg_hash_ja.h | 8 +++ intl/msg_hash_ko.h | 12 ++++- intl/msg_hash_lbl.h | 16 ++++-- intl/msg_hash_nl.h | 12 ++++- intl/msg_hash_pl.h | 16 ++++-- intl/msg_hash_pt_br.h | 12 ++++- intl/msg_hash_pt_pt.h | 14 ++++-- intl/msg_hash_ru.h | 20 +++++--- intl/msg_hash_us.h | 8 +++ intl/msg_hash_vn.h | 12 ++++- menu/menu_driver.c | 15 +++++- msg_hash.h | 8 +++ retroarch.c | 6 +-- 24 files changed, 315 insertions(+), 66 deletions(-) diff --git a/command.c b/command.c index 837929f506..01ad56ccf1 100644 --- a/command.c +++ b/command.c @@ -2477,6 +2477,13 @@ TODO: Add a setting for these tweaks */ if (!is_idle) video_driver_cached_frame(); + +#ifdef HAVE_DISCORD + discord_userdata_t userdata; + userdata.status = DISCORD_PRESENCE_GAME_PAUSED; + + command_event(CMD_EVENT_DISCORD_UPDATE, &userdata); +#endif } else { diff --git a/discord/discord.c b/discord/discord.c index 387a5b6cbb..a3dadd4e1d 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -25,11 +25,15 @@ #include "../msg_hash.h" -static const char* APPLICATION_ID = "475456035851599874"; +//static const char* APPLICATION_ID = "475456035851599874"; +static const char* APPLICATION_ID = "479875712363528207"; static int FrustrationLevel = 0; + static int64_t start_time = 0; +static int64_t pause_time = 0; static bool discord_ready = false; +static bool in_menu = false; static unsigned discord_status = 0; DiscordRichPresence discord_presence; @@ -75,7 +79,10 @@ static void handle_discord_join_request(const DiscordUser* request) void discord_update(enum discord_presence presence) { rarch_system_info_t *system = runloop_get_system_info(); - core_info_t *core_info = NULL; + core_info_t *core_info = NULL; + bool skip = false; + + core_info_get_current_core(&core_info); if (!discord_ready) return; @@ -85,25 +92,33 @@ void discord_update(enum discord_presence presence) (discord_status == presence)) return; - RARCH_LOG("[Discord] updating (%d)\n", presence); - memset(&discord_presence, 0, sizeof(discord_presence)); switch (presence) { case DISCORD_PRESENCE_MENU: - discord_presence.state = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU); - discord_presence.largeImageKey = "base"; - discord_presence.instance = 0; - discord_presence.startTimestamp = start_time; - break; - case DISCORD_PRESENCE_GAME: - core_info_get_current_core(&core_info); + discord_presence.details = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU); + discord_presence.largeImageKey = "base"; + discord_presence.largeImageText = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE); + discord_presence.instance = 0; + in_menu = true; + break; + case DISCORD_PRESENCE_GAME_PAUSED: + discord_presence.smallImageKey = "paused"; + discord_presence.smallImageText = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED); + discord_presence.details = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED); + + pause_time = time(0); + skip = true; + + if (in_menu) + break; + case DISCORD_PRESENCE_GAME: if (core_info) { - const char *system_name = string_replace_substring( - string_to_lower(core_info->core_name), " ", "_"); + const char *core_name = core_info->core_name ? core_info->core_name : "core"; + const char *system_name = string_replace_substring(string_to_lower((char *)core_name), " ", "_"); char *label = NULL; playlist_t *current_playlist = playlist_get_cached(); @@ -114,20 +129,69 @@ void discord_update(enum discord_presence presence) if (!label) label = (char *)path_basename(path_get(RARCH_PATH_BASENAME)); - - start_time = time(0); - discord_presence.state = core_info->display_name; - discord_presence.details = label; #if 1 - RARCH_LOG("[Discord] system name: %s\n", system_name); + RARCH_LOG("[Discord] current core: %s\n", system_name); RARCH_LOG("[Discord] current content: %s\n", label); #endif - discord_presence.largeImageKey = system_name; - discord_presence.smallImageKey = "base"; - discord_presence.instance = 0; - discord_presence.startTimestamp = start_time; + /* + At the present time, there is no consistent or clean way to present what platform + or core the user is playing on/with. If we were to present the platform as an icon, + some cores have multiple platforms, such as Dolphin with the GC or Wii, or blueMSX + with the MSX or MSX2. The libretro API has no way of determining what platform a + selected content is associated with; it only knows what core it's playing under. + The platform is determined by the core itself during initialization, not viewable + by the libretro API. A solution to this problem would be associating the content + with the first platform available in the core's information file, but that solution + doesn't work when someone sees another users playing Super Mario Galaxy with a + GameCube icon. It's not good enough. Another solution would be exposing what + platform is associated with inside the core itself, visible through the libretro + API, but this would require updating every libretro core to support this feature, + and the support would be too slow and limited for it to really work as a solution. + If we were to present the core as an icon, there are a few options available, and + none of them are desirable either. If we were to provide an icon for each core based + on that core's logo or name, then we'd need new assets for every single libretro + core available, AND each asset would need to be consistent with each other, in a + similar vein to the XMB themes of RetroArch, which would be another massive + undertaking. If we were to provide an icon for each core based on that core's + platform, then we have the same issue as earlier, except this time we're additionally + limited by the amount of assets a Discord RPC application is allowed to have: 150. + There are currently 173 core information files available within RetroArch, which goes + over that number by a bit. Now if that were determined by platform instead of core, + that number goes significantly down as there are many cores with multiple platforms, + but then we have the issue as described earlier. + + Because of this dilemma, for now the provided icon for the In-Game status will be the + standard/default "core" icon, at least we can come up with a solution that's clean + and consistent. When such a time presents itself, the below line will be uncommented. + */ + + //discord_presence.largeImageKey = system_name; + discord_presence.largeImageKey = "core"; + + if (core_info->display_name) + discord_presence.largeImageText = core_info->display_name; + + if (in_menu) + start_time = time(0); + else + start_time = start_time + difftime(time(0), pause_time); + + RARCH_LOG("%d\n", start_time); + + if (!skip) + { + discord_presence.smallImageKey = "playing"; + discord_presence.smallImageText = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING); + discord_presence.startTimestamp = start_time; + discord_presence.details = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME); + } + + discord_presence.state = label; + discord_presence.instance = 0; } + + in_menu = false; break; case DISCORD_PRESENCE_NETPLAY_HOSTING: case DISCORD_PRESENCE_NETPLAY_CLIENT: @@ -135,6 +199,12 @@ void discord_update(enum discord_presence presence) /* TODO/FIXME */ break; } + + if (in_menu && skip) + return; + + RARCH_LOG("[Discord] updating (%d)\n", presence); + Discord_UpdatePresence(&discord_presence); discord_status = presence; } diff --git a/discord/discord.h b/discord/discord.h index 8b5c96050b..84aa87f8ad 100644 --- a/discord/discord.h +++ b/discord/discord.h @@ -34,6 +34,7 @@ enum discord_presence { DISCORD_PRESENCE_MENU = 0, DISCORD_PRESENCE_GAME, + DISCORD_PRESENCE_GAME_PAUSED, DISCORD_PRESENCE_CHEEVO_UNLOCKED, DISCORD_PRESENCE_NETPLAY_HOSTING, DISCORD_PRESENCE_NETPLAY_CLIENT diff --git a/intl/msg_hash_ar.h b/intl/msg_hash_ar.h index 3653d191b7..881210a828 100644 --- a/intl/msg_hash_ar.h +++ b/intl/msg_hash_ar.h @@ -3456,9 +3456,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Enable background filler thickness") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Show Rewind Settings") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3517,6 +3517,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Clear") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/intl/msg_hash_chs.h b/intl/msg_hash_chs.h index 2b0cda9c45..c8ff8960de 100644 --- a/intl/msg_hash_chs.h +++ b/intl/msg_hash_chs.h @@ -3240,9 +3240,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Enable background filler thickness") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Show Rewind Settings") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3301,6 +3301,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Clear") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/intl/msg_hash_cht.h b/intl/msg_hash_cht.h index fbf997e55e..dcc7565720 100644 --- a/intl/msg_hash_cht.h +++ b/intl/msg_hash_cht.h @@ -3232,9 +3232,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Enable background filler thickness") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Show Rewind Settings") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3293,6 +3293,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Clear") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index 69e95be72a..239899abab 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -3342,9 +3342,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Enable background filler thickness") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Show Rewind Settings") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3403,6 +3403,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Clear") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/intl/msg_hash_eo.h b/intl/msg_hash_eo.h index bc2fe52fa5..e157edfc74 100644 --- a/intl/msg_hash_eo.h +++ b/intl/msg_hash_eo.h @@ -3107,9 +3107,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Enable background filler thickness") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Show Rewind Settings") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3168,6 +3168,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Clear") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 7341519c4b..4eba0b39b9 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -6578,6 +6578,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "En-Menú" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "En-Juego" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "En-Juego (Pausado)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Jugando" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Pausado" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Activar Discord" diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index d0b3503a0b..b5d3ab766a 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -3266,9 +3266,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Enable background filler thickness") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Show Rewind Settings") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3327,6 +3327,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Clear") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index bb5b06fdbd..ec334aef13 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -3326,9 +3326,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Abilita lo spessore del riempimento dello sfondo") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "Solo per schermi CRT a 15 kHz. Tenta di utilizzare la risoluzione esatta core/gioco e la frequenza di aggiornamento.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "Quando CRT SwitchRes è abilitato, forza la risoluzione orizzontale ultrawide per minimizzare il cambio di modalità.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Risoluzione") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Risoluzione") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Mostra impostazioni di riavvolgimento") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3387,6 +3387,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Cancella") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Abilita Discord" diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 73b6cf9f35..a7813f2e9a 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3662,6 +3662,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "クリア") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Discordを有効" diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index 31c7e48614..f867b18e6c 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -3227,9 +3227,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Enable background filler thickness") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Show Rewind Settings") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3288,6 +3288,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Clear") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 1077bb08a3..1dac8eef33 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1141,10 +1141,10 @@ MSG_HASH(MENU_ENUM_LABEL_USE_THIS_DIRECTORY, "use_this_directory") MSG_HASH(MENU_ENUM_LABEL_VIDEO_ALLOW_ROTATE, "video_allow_rotate") -MSG_HASH(MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION, - "crt_switch_resolution") -MSG_HASH(MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, - "crt_switch_resolution_super") +MSG_HASH(MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION, + "crt_switch_resolution") +MSG_HASH(MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, + "crt_switch_resolution_super") MSG_HASH(MENU_ENUM_LABEL_VIDEO_ASPECT_RATIO, "video_aspect_ratio") MSG_HASH(MENU_ENUM_LABEL_VIDEO_ASPECT_RATIO_AUTO, @@ -1545,6 +1545,14 @@ MSG_HASH(MENU_ENUM_LABEL_DEFERRED_QUICK_MENU_OVERRIDE_OPTIONS, "deferred_quick_menu_override_options") MSG_HASH(MENU_ENUM_LABEL_DISCORD_IN_MENU, "discord_in_menu") +MSG_HASH(MENU_ENUM_LABEL_DISCORD_IN_GAME, + "discord_in_game") +MSG_HASH(MENU_ENUM_LABEL_DISCORD_IN_GAME_PAUSED, + "discord_in_game_paused") +MSG_HASH(MENU_ENUM_LABEL_DISCORD_STATUS_PLAYING, + "discord_status_playing") +MSG_HASH(MENU_ENUM_LABEL_DISCORD_STATUS_PAUSED, + "discord_status_paused") MSG_HASH(MENU_ENUM_LABEL_MIDI_INPUT, "midi_input") MSG_HASH(MENU_ENUM_LABEL_MIDI_OUTPUT, diff --git a/intl/msg_hash_nl.h b/intl/msg_hash_nl.h index 4fcbdd1f8a..63f5d9db7a 100644 --- a/intl/msg_hash_nl.h +++ b/intl/msg_hash_nl.h @@ -3109,9 +3109,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Enable background filler thickness") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Show Rewind Settings") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3170,6 +3170,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Clear") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/intl/msg_hash_pl.h b/intl/msg_hash_pl.h index e929c3004e..a5f446850f 100644 --- a/intl/msg_hash_pl.h +++ b/intl/msg_hash_pl.h @@ -3524,10 +3524,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, "Włącz grubość wypełniacza") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Włącz grubość wypełniacza tła") -MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "Tylko dla wyświetlaczy CRT 15 kHz. Próby użycia dokładnej rozdzielczości rdzenia/gry i częstotliwości odświeżania.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT Przełącz rozdzielczość") -MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "Po włączeniu przełączników CRT wymuś ultrafioletową rozdzielczość poziomą, aby zminimalizować przełączanie trybu.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super rozdzielczość") +MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "Tylko dla wyświetlaczy CRT 15 kHz. Próby użycia dokładnej rozdzielczości rdzenia/gry i częstotliwości odświeżania.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT Przełącz rozdzielczość") +MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "Po włączeniu przełączników CRT wymuś ultrafioletową rozdzielczość poziomą, aby zminimalizować przełączanie trybu.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super rozdzielczość") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Pokaż ustawienia przewijania") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3586,6 +3586,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Oczyść") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "W Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "W Grze") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "W Grze (Wstrzymano)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Gra") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Wstrzymano") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Włącz Discord" diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index 1ce0e087c4..95d3fb5769 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -2056,7 +2056,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_HELP_LIST, MSG_HASH(MSG_ADDED_TO_FAVORITES, "Adicionado aos favoritos") MSG_HASH(MSG_RESET_CORE_ASSOCIATION, - "A associação do núcleo de entrada da lista de reprodução foi redefinida.") + "A associação do núcleo de entrada da lista de reprodução foi redefinida.") MSG_HASH(MSG_APPENDED_DISK, "Disco anexado") MSG_HASH(MSG_APPLICATION_DIR, @@ -3561,7 +3561,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_ENABLE_MENU, MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_SETTINGS, "Configurações do Mixer") MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_SETTINGS, - "Visualizar e/ou modificar as configurações do mixer de áudio.") + "Visualizar e/ou modificar as configurações do mixer de áudio.") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_INFO, "Informação") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_FILE, @@ -3724,6 +3724,14 @@ MSG_HASH(MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, "Continuar conquistas para a sessão atual (Esta ação desabilitará Estados de Jogos, Trapaças, Rebobinagem, Pausa e Câmera Lenta e reiniciará o jogo atual).") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "No Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "No Jogo") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "No Jogo (Pausado)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Jogando") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Pausado") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Habilitar o Discord" diff --git a/intl/msg_hash_pt_pt.h b/intl/msg_hash_pt_pt.h index b79ce142cf..c20eaff54a 100644 --- a/intl/msg_hash_pt_pt.h +++ b/intl/msg_hash_pt_pt.h @@ -2505,7 +2505,7 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FORCE_SRGB_DISABLE, "Desativar o suporte de sRGB FBO. Alguns controladores Intel OpenGL para o Windows possuem problemas de vídeo em sRGB FBO, se o mesmo estiver ativo. Ao ativar esta opção, poderá resolver esse problema." ) -MSG_HASH( +MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN, "Executar em ecrã completo. Esta definição poderá ser alterada a qualquer momento." ) @@ -3201,9 +3201,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Enable background filler thickness") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Show Rewind Settings") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3262,6 +3262,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Clear") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index ea5cb8c63f..d18c31f741 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -3326,6 +3326,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Очистить") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Включить Discord") MSG_HASH(MENU_ENUM_SUBLABEL_DISCORD_ALLOW, @@ -3366,14 +3374,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, "Включить толщину заполнителя границ") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Включить фон заполнителя границ") -MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, +MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "Только для 15 кГц CRT дисплеев. Пытается использовать точное разрешение и частоту обновления ядра/игры.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, - "CRT SwitchRes") -MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, + "CRT SwitchRes") +MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "Когда CRT SwitchRes включен, принудительно устанавливает ультраширокое горизонтальное разрешение чтобы минимизировать изменение режима.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, - "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, + "CRT Super Resolution") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, "Показывать клавиатуру/контроллер на оверлее.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 0590f8d60d..97ec622c3d 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3922,6 +3922,14 @@ MSG_HASH(MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, "Resume achievements for current session (This action will disable savestates, cheats, rewind, pause, and slow-motion and reset the current game).") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/intl/msg_hash_vn.h b/intl/msg_hash_vn.h index 71b81df5b7..9cd2329191 100644 --- a/intl/msg_hash_vn.h +++ b/intl/msg_hash_vn.h @@ -3264,9 +3264,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, "Enable background filler thickness") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, "CRT SwitchRes") MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, "CRT Super Resolution") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Show Rewind Settings") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, @@ -3325,6 +3325,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, "Clear") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, "In-Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "In-Game") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "In-Game (Paused)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Playing") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Paused") MSG_HASH( MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, "Enable Discord" diff --git a/menu/menu_driver.c b/menu/menu_driver.c index a3033c9c36..effc75d61a 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -29,6 +29,10 @@ #include #endif +#ifdef HAVE_DISCORD +#include "discord/discord.h" +#endif + #ifdef HAVE_CONFIG_H #include "../config.h" #endif @@ -458,11 +462,18 @@ bool menu_display_libretro(bool is_idle, input_driver_set_libretro_input_blocked(); core_run(); - input_driver_unset_libretro_input_blocked(); + return true; } +#ifdef HAVE_DISCORD + discord_userdata_t userdata; + userdata.status = DISCORD_PRESENCE_GAME_PAUSED; + + command_event(CMD_EVENT_DISCORD_UPDATE, &userdata); +#endif + if (is_idle) return true; /* Maybe return false here for indication of idleness? */ @@ -1472,7 +1483,7 @@ void menu_display_draw_keyboard( } menu_display_draw_text(font, grid[i], - width/2.0 - (11*ptr_width)/2.0 + (i % 11) + width/2.0 - (11*ptr_width)/2.0 + (i % 11) * ptr_width + ptr_width/2.0, height/2.0 + ptr_height + line_y + font->size / 3, width, height, 0xffffffff, TEXT_ALIGN_CENTER, 1.0f, diff --git a/msg_hash.h b/msg_hash.h index 1a6f5c78f0..52e322ae96 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -426,6 +426,14 @@ enum msg_hash_enums MENU_ENUM_LABEL_DISCORD_IN_MENU, MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, + MENU_ENUM_LABEL_DISCORD_IN_GAME, + MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + MENU_ENUM_LABEL_DISCORD_IN_GAME_PAUSED, + MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + MENU_ENUM_LABEL_DISCORD_STATUS_PLAYING, + MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + MENU_ENUM_LABEL_DISCORD_STATUS_PAUSED, + MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY, MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_LOOPED, diff --git a/retroarch.c b/retroarch.c index 90823fe9f3..99005efb16 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2710,7 +2710,7 @@ static enum runloop_state runloop_check_state( } else { - if ( global->menu.prev_action == action && + if ( global->menu.prev_action == action && global->menu.noop_press_time < 200000) /* 250ms */ { global->menu.action_start_time = global->menu.prev_start_time ; @@ -3442,7 +3442,7 @@ int runloop_iterate(unsigned *sleep_ms) end: { retro_time_t to_sleep_ms; - + if (settings->bools.vrr_runloop_enable) { struct retro_system_av_info *av_info = @@ -3467,7 +3467,7 @@ int runloop_iterate(unsigned *sleep_ms) if (!settings->floats.fastforward_ratio && runloop_fastmotion) return 0; - frame_limit_minimum_time = + frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * (runloop_fastmotion ? settings->floats.fastforward_ratio : 1.0f))); } From ea6541b90f1eb218ca9bb0d68cc5ddcdab54012b Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Sat, 18 Aug 2018 02:17:08 -0500 Subject: [PATCH 076/182] discord: remove test rpc client ID --- discord/discord.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/discord/discord.c b/discord/discord.c index a3dadd4e1d..f1f81d9fdd 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -25,8 +25,7 @@ #include "../msg_hash.h" -//static const char* APPLICATION_ID = "475456035851599874"; -static const char* APPLICATION_ID = "479875712363528207"; +static const char* APPLICATION_ID = "475456035851599874"; static int FrustrationLevel = 0; static int64_t start_time = 0; From 0e34c12d5c8ea2f861dc29df240c1dc68657d2cf Mon Sep 17 00:00:00 2001 From: Dwedit Date: Sat, 18 Aug 2018 08:40:19 -0500 Subject: [PATCH 077/182] Fixed bug that let Retroarch proceed to retro_run without loading content Removed unlocalized and redundant error message --- tasks/task_content.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tasks/task_content.c b/tasks/task_content.c index 4ca0f0ba67..e67de039d3 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -814,6 +814,11 @@ static bool content_file_init( free(info); } + else if (special == NULL) + { + *error_string = strdup(msg_hash_to_str(MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT)); + ret = false; + } return ret; } @@ -874,7 +879,6 @@ static bool task_load_content(content_ctx_info_t *content_info, if (!content_load(content_info)) { - *error_string = strdup("This core requires a content file, could not load content.\n"); return false; } From 646e64c28caf394306121ff7d9d58a0616e0f718 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 18 Aug 2018 15:56:44 +0200 Subject: [PATCH 078/182] Fix some clang scan-build warnings/errors --- discord/discord.c | 1 - gfx/drivers/vulkan.c | 10 ++++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/discord/discord.c b/discord/discord.c index 387a5b6cbb..7336fb5ad5 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -74,7 +74,6 @@ static void handle_discord_join_request(const DiscordUser* request) void discord_update(enum discord_presence presence) { - rarch_system_info_t *system = runloop_get_system_info(); core_info_t *core_info = NULL; if (!discord_ready) diff --git a/gfx/drivers/vulkan.c b/gfx/drivers/vulkan.c index a4f2c55267..48db5e2508 100644 --- a/gfx/drivers/vulkan.c +++ b/gfx/drivers/vulkan.c @@ -2228,10 +2228,16 @@ static void vulkan_set_osd_msg(void *data, static uintptr_t vulkan_load_texture(void *video_data, void *data, bool threaded, enum texture_filter_type filter_type) { + struct vk_texture *texture = NULL; vk_t *vk = (vk_t*)video_data; struct texture_image *image = (struct texture_image*)data; - struct vk_texture *texture = (struct vk_texture*)calloc(1, sizeof(*texture)); - if (!image || !texture) + if (!image) + return 0; + + texture = (struct vk_texture*) + calloc(1, sizeof(*texture)); + + if (!texture) return 0; if (!image->pixels || !image->width || !image->height) From 90efa027180dfa7769cc10bbda35be2d35f49ac4 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 18 Aug 2018 16:15:55 +0200 Subject: [PATCH 079/182] Fix more scan-build issues --- configuration.c | 2 +- gfx/drivers/vulkan.c | 3 +-- verbosity.c | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/configuration.c b/configuration.c index af8979c63f..cd33faec0d 100644 --- a/configuration.c +++ b/configuration.c @@ -1480,7 +1480,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, static struct config_float_setting *populate_settings_float(settings_t *settings, int *size) { unsigned count = 0; - struct config_float_setting *tmp = (struct config_float_setting*)malloc((*size + 1) * sizeof(struct config_float_setting)); + struct config_float_setting *tmp = (struct config_float_setting*)calloc(1, (*size + 1) * sizeof(struct config_float_setting)); SETTING_FLOAT("video_aspect_ratio", &settings->floats.video_aspect_ratio, true, aspect_ratio, false); SETTING_FLOAT("video_scale", &settings->floats.video_scale, false, 0.0f, false); diff --git a/gfx/drivers/vulkan.c b/gfx/drivers/vulkan.c index 48db5e2508..f9fb7095c0 100644 --- a/gfx/drivers/vulkan.c +++ b/gfx/drivers/vulkan.c @@ -808,8 +808,7 @@ static bool vulkan_init_filter_chain_preset(vk_t *vk, const char *shader_path) static bool vulkan_init_filter_chain(vk_t *vk) { - settings_t *settings = config_get_ptr(); - const char *shader_path = retroarch_get_shader_preset(); + const char *shader_path = retroarch_get_shader_preset(); enum rarch_shader_type type = video_shader_parse_type(shader_path, RARCH_SHADER_NONE); diff --git a/verbosity.c b/verbosity.c index 7b76838eb1..4b8dd7cc92 100644 --- a/verbosity.c +++ b/verbosity.c @@ -214,8 +214,8 @@ void RARCH_LOG_V(const char *tag, const char *fmt, va_list ap) void RARCH_LOG_BUFFER(uint8_t *data, size_t size) { unsigned i, offset; - int padding = size % 16; - uint8_t buf[16]; + int padding = size % 16; + uint8_t buf[16] = {0}; RARCH_LOG("== %d-byte buffer ==================\n", size); From e4834250b9815b7931270cf91b88aa76651d7078 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 12:39:17 -0400 Subject: [PATCH 080/182] Qt: set shader dialog title to current preset/shader name --- gfx/video_shader_parse.c | 2 ++ gfx/video_shader_parse.h | 1 + ui/drivers/qt/shaderparamsdialog.cpp | 16 ++++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index a70d539c1f..33e0c1674c 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -748,6 +748,8 @@ bool video_shader_read_conf_cgp(config_file_t *conf, shader->passes = MIN(shaders, GFX_MAX_SHADERS); attr.i = 0; + strlcpy(shader->path, conf->path, sizeof(shader->path)); + if (settings->bools.video_shader_watch_files) { if (file_change_data) diff --git a/gfx/video_shader_parse.h b/gfx/video_shader_parse.h index 744c7c9ab2..15d228a44f 100644 --- a/gfx/video_shader_parse.h +++ b/gfx/video_shader_parse.h @@ -147,6 +147,7 @@ struct video_shader char prefix[64]; char script_class[512]; char script_path[PATH_MAX_LENGTH]; + char path[PATH_MAX_LENGTH]; char *script; /* Dynamically allocated. Must be free'd. Only used by XML. */ bool modern; /* Only used for XML shaders. */ diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 98e532c1bd..6ece4fb62d 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -14,6 +14,7 @@ #include "../ui_qt.h" extern "C" { +#include #include "../../../command.h" #ifdef HAVE_MENU #include "../../../menu/menu_shader.h" @@ -284,6 +285,7 @@ void ShaderParamsDialog::reload() { struct video_shader *menu_shader = NULL; struct video_shader *video_shader = NULL; + const char *shader_path = NULL; int i; unsigned j; @@ -295,10 +297,24 @@ void ShaderParamsDialog::reload() */ if ((video_shader && video_shader->passes == 0) || !video_shader) + { + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); goto end; + } clearLayout(m_layout); + /* Only check video_shader for the path, menu_shader seems stale... e.g. if you remove all the shader passes, + * it still has the old path in it, but video_shader does not + */ + if (!string_is_empty(video_shader->path)) + { + shader_path = video_shader->path; + setWindowTitle(QFileInfo(shader_path).completeBaseName()); + } + else + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); + /* NOTE: We assume that parameters are always grouped in order by the pass number, e.g., all parameters for pass 0 come first, then params for pass 1, etc. */ for (i = 0; i < static_cast(video_shader->passes); i++) { From e78f2f63f71e07557e4884af5ffde1fcb39f12d3 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 12:39:28 -0400 Subject: [PATCH 081/182] Qt: fix changing of double spinbox values --- ui/drivers/qt/shaderparamsdialog.cpp | 42 +++++++++++++++++++++------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 6ece4fb62d..3e4d712acd 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -586,7 +586,6 @@ void ShaderParamsDialog::onShaderParamSpinBoxValueChanged(int value) QSlider *slider = NULL; struct video_shader *menu_shader = NULL; struct video_shader *video_shader = NULL; - double newValue = 0.0; getShaders(&menu_shader, &video_shader); @@ -612,6 +611,8 @@ void ShaderParamsDialog::onShaderParamSpinBoxValueChanged(int value) if (ok) { + double newValue = 0.0; + if (menu_shader) { struct video_shader_parameter *param = &menu_shader->parameters[parameter]; @@ -643,8 +644,10 @@ void ShaderParamsDialog::onShaderParamDoubleSpinBoxValueChanged(double value) QVariant sliderVariant; QVariant paramVariant; QSlider *slider = NULL; - struct video_shader_parameter *param = NULL; - double newValue = 0.0; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + + getShaders(&menu_shader, &video_shader); if (!doubleSpinBox) return; @@ -663,15 +666,34 @@ void ShaderParamsDialog::onShaderParamDoubleSpinBoxValueChanged(double value) if (paramVariant.isValid()) { - param = paramVariant.value(); + bool ok = false; + int parameter = paramVariant.toInt(&ok); - if (param) + if (ok) { - param->current = value; - newValue = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); - slider->blockSignals(true); - slider->setValue(newValue); - slider->blockSignals(false); + double newValue = 0.0; + + if (menu_shader) + { + struct video_shader_parameter *param = &menu_shader->parameters[parameter]; + + param->current = value; + newValue = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); + slider->blockSignals(true); + slider->setValue(newValue); + slider->blockSignals(false); + } + + if (video_shader) + { + struct video_shader_parameter *param = &video_shader->parameters[parameter]; + + param->current = value; + newValue = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); + slider->blockSignals(true); + slider->setValue(newValue); + slider->blockSignals(false); + } } } } From 0a9891def1571580adaa8538e8ed778a08d23c55 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 13:00:39 -0400 Subject: [PATCH 082/182] Qt: fix checkbox setting of shader parameters --- ui/drivers/qt/shaderparamsdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 3e4d712acd..5cf5bb89db 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -408,7 +408,7 @@ void ShaderParamsDialog::addShaderParam(struct video_shader_parameter *param, in /* option is basically a bool, so use a checkbox */ QCheckBox *checkBox = new QCheckBox(this); checkBox->setChecked(param->current == param->maximum ? true : false); - checkBox->setProperty("pass", param->pass); + checkBox->setProperty("param", parameter); connect(checkBox, SIGNAL(clicked()), this, SLOT(onShaderParamCheckBoxClicked())); @@ -479,7 +479,7 @@ void ShaderParamsDialog::onShaderParamCheckBoxClicked() if (menu_shader && menu_shader->passes == 0) return; - paramVariant = checkBox->property("parameter"); + paramVariant = checkBox->property("param"); if (paramVariant.isValid()) { From 894d460821b87618afb153064855320b9cb28cf8 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 13:04:53 -0400 Subject: [PATCH 083/182] Qt: add "current shader" prefix to window title --- intl/msg_hash_ja.h | 2 ++ intl/msg_hash_us.h | 2 ++ msg_hash.h | 1 + ui/drivers/qt/shaderparamsdialog.cpp | 2 +- 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 73b6cf9f35..33ce9f1920 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3754,3 +3754,5 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, "更新に失敗しました。") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT_CONTRIBUTORS, "作成者") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, + "現在のシェーダー") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 0590f8d60d..ae6b760e09 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -4256,3 +4256,5 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, "Update failed.") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT_CONTRIBUTORS, "Contributors") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, + "Current shader") diff --git a/msg_hash.h b/msg_hash.h index 1a6f5c78f0..8857983952 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1979,6 +1979,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY, MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED, MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, + MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 5cf5bb89db..c51bef5def 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -310,7 +310,7 @@ void ShaderParamsDialog::reload() if (!string_is_empty(video_shader->path)) { shader_path = video_shader->path; - setWindowTitle(QFileInfo(shader_path).completeBaseName()); + setWindowTitle(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER)) + ": " + QFileInfo(shader_path).fileName()); } else setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); From f01894ebe446507b19512ce7d907ecd6efc31df5 Mon Sep 17 00:00:00 2001 From: Dwedit Date: Sat, 18 Aug 2018 12:43:49 -0500 Subject: [PATCH 084/182] Attach console before displaying Version information, Help, or Features. --- retroarch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/retroarch.c b/retroarch.c index 90823fe9f3..de1298a024 100644 --- a/retroarch.c +++ b/retroarch.c @@ -375,6 +375,7 @@ static void global_free(void) static void retroarch_print_features(void) { + frontend_driver_attach_console(); puts(""); puts("Features:"); @@ -451,7 +452,7 @@ static void retroarch_print_features(void) static void retroarch_print_version(void) { char str[255]; - + frontend_driver_attach_console(); str[0] = '\0'; fprintf(stderr, "%s: %s -- v%s", @@ -473,6 +474,7 @@ static void retroarch_print_version(void) **/ static void retroarch_print_help(const char *arg0) { + frontend_driver_attach_console(); puts("==================================================================="); retroarch_print_version(); puts("==================================================================="); From 105fba6abe34e4edc04031300af1efe042181830 Mon Sep 17 00:00:00 2001 From: alfrix Date: Fri, 17 Aug 2018 19:38:18 -0300 Subject: [PATCH 085/182] XMB add an option to show desktop ui aka WIMP --- CHANGES.md | 4 +++- intl/msg_hash_es.h | 4 ++++ intl/msg_hash_us.h | 4 ++++ menu/cbs/menu_cbs_ok.c | 49 ++++++++++++++++++++++++----------------- menu/drivers/xmb.c | 11 ++++++++- menu/menu_displaylist.c | 22 ++++++++++-------- menu/menu_setting.c | 41 ++++++++++++++++++++-------------- msg_hash.h | 3 +++ 8 files changed, 91 insertions(+), 47 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0ddf01b29a..4adbdf50d1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -21,6 +21,8 @@ - MENU/QT/WIMP: Initial grid view. - MENU/QT/WIMP: Drag&drop to add new playlist items, add option to add/edit/delete playlists. - MENU/QT/WIMP: Add menu option to update RetroArch (Windows only for now). +- MENU/XMB: Add new icons for the settings +- MENU/XMB: Add an option to show the desktop ui - METAL: Initial work-in-progress video driver for Metal. macOS-only right now, and currently requires macOS 10.13. - METAL: Supports XMB/MaterialUI, has a menu display driver. Has a font rendering driver. - METAL/SLANG: Slang shaders should be compatible with Metal video driver. @@ -91,7 +93,7 @@ video drivers that implement it (D3D8/9/10/11/12/GL) - MENU/RGUI: D3D8/D3D9: Hookup Menu Linear Filter - MENU/XMB: Disable XMB shadow icons by default for PowerPC and ARM for performance reasons. - MENU/XMB: Left/right thumbnails are now automatically scaled according to layout. -- MENU/XMB: Add Left Thumbnails (additional to the right). +- MENU/XMB: Add Left Thumbnails (additional to the right). - MENU/XMB: Fixed left/right tab regression. - MENU/XMB: Fix scaling of tall images that were cut on bottom previously. - MENU/XMB: Menu scale factor setting now changes texts length, image scaling and margins. diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 7341519c4b..624674b829 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -6417,6 +6417,10 @@ MSG_HASH( "

  • reiniciar RetroArch si actualizaste algo con el \"Actualizador en línea\"
  • \n" "Por último, el contenido debe coincidir las bases de datos existente de aquí. Si aún no funciona, considere enviar un reporte de error." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + "Mostrar intefaz de escritorio" + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index ae6b760e09..6cfc4fb91c 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3839,6 +3839,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, "
  • have \"Databases\" updated via Online Updater
  • \n" "
  • restart RetroArch if any of the above was just done
  • \n" "Finally, the content must match existing databases from here. If it is still not working, consider submitting a bug report.") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + "Show Desktop UI" + ) #endif MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, "Don't show this again") diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 5991b04d77..6135befeed 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -88,6 +88,9 @@ enum ACTION_OK_SET_PATH_VIDEO_FILTER, ACTION_OK_SET_PATH_OVERLAY, ACTION_OK_SET_DIRECTORY, +#ifdef HAVE_QT + ACTION_OK_SHOW_WIMP, +#endif ACTION_OK_LOAD_CHEAT_FILE_APPEND }; @@ -820,11 +823,11 @@ int generic_action_ok_displaylist_push(const char *path, case ACTION_OK_DL_DEFERRED_CORE_LIST_SET: info.directory_ptr = idx; menu->scratchpad.unsigned_var = (unsigned)idx; - info_path = + info_path = settings->paths.directory_libretro; info_label = msg_hash_to_str( MENU_ENUM_LABEL_DEFERRED_CORE_LIST_SET); - info.enum_idx = + info.enum_idx = MENU_ENUM_LABEL_DEFERRED_CORE_LIST_SET; dl_type = DISPLAYLIST_GENERIC; break; @@ -1525,7 +1528,7 @@ static int action_ok_file_load(const char *path, if (filebrowser_get_type() == FILEBROWSER_SELECT_FILE_SUBSYSTEM) { - /* TODO/FIXME - this path is triggered when we try to load a + /* TODO/FIXME - this path is triggered when we try to load a * file from an archive while inside the load subsystem * action */ menu_handle_t *menu = NULL; @@ -1676,7 +1679,7 @@ static int action_ok_playlist_entry_collection(const char *path, core_info.inf->display_name, NULL, NULL); - } + } else strlcpy(new_core_path, core_path, sizeof(new_core_path)); @@ -1750,7 +1753,7 @@ static int action_ok_playlist_entry(const char *path, core_info.inf->display_name, NULL, NULL); - + } else if (!string_is_empty(core_path)) strlcpy(new_core_path, core_path, sizeof(new_core_path)); @@ -1813,9 +1816,9 @@ static int action_ok_playlist_entry_start_content(const char *path, if (!core_info_find(&core_info, new_core_path)) found_associated_core = false; - /* TODO: figure out if this should refer to + /* TODO: figure out if this should refer to * the inner or outer entry_path. */ - /* TODO: make sure there's only one entry_path + /* TODO: make sure there's only one entry_path * in this function. */ if (!found_associated_core) return action_ok_file_load_with_detect_core(entry_path, @@ -2111,7 +2114,7 @@ static void menu_input_st_string_cb_rename_entry(void *userdata, NULL); } - + menu_input_dialog_end(); } @@ -2719,7 +2722,7 @@ static int action_ok_cheat_add_bottom(const char *path, cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_RETRO); msg[0] = '\0'; - strlcpy(msg, + strlcpy(msg, msg_hash_to_str(MSG_CHEAT_ADD_BOTTOM_SUCCESS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; @@ -3167,7 +3170,6 @@ static void cb_generic_dir_download(void *task_data, void *user_data, const char *err) { file_transfer_t *transf = (file_transfer_t*)user_data; - if (transf) { generic_action_ok_network(transf->path, transf->path, 0, 0, 0, @@ -3521,15 +3523,17 @@ int (func_name)(const char *path, const char *label, unsigned type, size_t idx, return generic_action_ok_command(cmd); \ } -default_action_ok_cmd_func(action_ok_cheat_apply_changes,CMD_EVENT_CHEATS_APPLY) -default_action_ok_cmd_func(action_ok_quit, CMD_EVENT_QUIT) -default_action_ok_cmd_func(action_ok_save_new_config, CMD_EVENT_MENU_SAVE_CONFIG) -default_action_ok_cmd_func(action_ok_resume_content, CMD_EVENT_RESUME) -default_action_ok_cmd_func(action_ok_restart_content, CMD_EVENT_RESET) -default_action_ok_cmd_func(action_ok_screenshot, CMD_EVENT_TAKE_SCREENSHOT) -default_action_ok_cmd_func(action_ok_disk_cycle_tray_status, CMD_EVENT_DISK_EJECT_TOGGLE ) -default_action_ok_cmd_func(action_ok_shader_apply_changes, CMD_EVENT_SHADERS_APPLY_CHANGES ) - +default_action_ok_cmd_func(action_ok_cheat_apply_changes, CMD_EVENT_CHEATS_APPLY) +default_action_ok_cmd_func(action_ok_quit, CMD_EVENT_QUIT) +default_action_ok_cmd_func(action_ok_save_new_config, CMD_EVENT_MENU_SAVE_CONFIG) +default_action_ok_cmd_func(action_ok_resume_content, CMD_EVENT_RESUME) +default_action_ok_cmd_func(action_ok_restart_content, CMD_EVENT_RESET) +default_action_ok_cmd_func(action_ok_screenshot, CMD_EVENT_TAKE_SCREENSHOT) +default_action_ok_cmd_func(action_ok_disk_cycle_tray_status, CMD_EVENT_DISK_EJECT_TOGGLE) +default_action_ok_cmd_func(action_ok_shader_apply_changes, CMD_EVENT_SHADERS_APPLY_CHANGES) +#ifdef HAVE_QT +default_action_ok_cmd_func(action_ok_show_wimp, CMD_EVENT_UI_COMPANION_TOGGLE) +#endif static int action_ok_reset_core_association(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) @@ -3944,7 +3948,7 @@ void netplay_refresh_rooms_menu(file_list_t *list) char country[PATH_MAX_LENGTH] = {0}; if (*netplay_room_list[i].country) - string_add_between_pairs(country, netplay_room_list[i].country, + string_add_between_pairs(country, netplay_room_list[i].country, sizeof(country)); /* Uncomment this to debug mismatched room parameters*/ @@ -4739,6 +4743,11 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS: BIND_ACTION_OK(cbs, action_ok_enable_settings); break; +#ifdef HAVE_QT + case MENU_ENUM_LABEL_SHOW_WIMP: + BIND_ACTION_OK(cbs, action_ok_show_wimp); + break; +#endif case MENU_ENUM_LABEL_QUIT_RETROARCH: BIND_ACTION_OK(cbs, action_ok_quit); break; diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 6584de207f..ceccd0aa8e 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2359,6 +2359,9 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, return xmb->textures.list[XMB_TEXTURE_RECORD]; case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS: return xmb->textures.list[XMB_TEXTURE_OSD]; +#ifdef HAVE_QT + case MENU_ENUM_LABEL_SHOW_WIMP: +#endif case MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS: return xmb->textures.list[XMB_TEXTURE_UI]; case MENU_ENUM_LABEL_POWER_MANAGEMENT_SETTINGS: @@ -5263,6 +5266,13 @@ static int xmb_list_push(void *data, void *userdata, entry.enum_idx = MENU_ENUM_LABEL_ADD_CONTENT_LIST; menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); +#ifdef HAVE_QT + if (settings->bools.desktop_menu_enable) + { + entry.enum_idx = MENU_ENUM_LABEL_SHOW_WIMP; + menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); + } +#endif #if defined(HAVE_NETWORKING) { settings_t *settings = config_get_ptr(); @@ -5307,7 +5317,6 @@ static int xmb_list_push(void *data, void *userdata, entry.enum_idx = MENU_ENUM_LABEL_HELP_LIST; menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); } - #if !defined(IOS) if (settings->bools.menu_show_quit_retroarch) { diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 962eedebbf..1801b78e16 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4857,7 +4857,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) string_is_equal(core_path, path_get(RARCH_PATH_CORE))) { strlcpy(new_path_entry, core_path, sizeof(new_path_entry)); - snprintf(new_entry, sizeof(new_entry), "%s (%s)", + snprintf(new_entry, sizeof(new_entry), "%s (%s)", msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DETECT_CORE_LIST_OK_CURRENT_CORE), core_name); new_lbl_entry[0] = '\0'; @@ -5538,7 +5538,11 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_SHOW_HELP, PARSE_ONLY_BOOL, false); - +#ifdef HAVE_QT + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SHOW_WIMP, + PARSE_ONLY_UINT, false); +#endif menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_SHOW_QUIT_RETROARCH, PARSE_ONLY_BOOL, false); @@ -6291,11 +6295,11 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_SCREEN_RESOLUTION, PARSE_ACTION, false); - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION, + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION, PARSE_ONLY_BOOL, false); - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, PARSE_ONLY_UINT, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_PAL60_ENABLE, @@ -6908,7 +6912,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) { settings_t *settings = config_get_ptr(); - if (settings->bools.quick_menu_show_save_core_overrides + if (settings->bools.quick_menu_show_save_core_overrides && !settings->bools.kiosk_mode_enable) { menu_entries_append_enum(info->list, @@ -6919,7 +6923,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) count++; } - if (settings->bools.quick_menu_show_save_content_dir_overrides + if (settings->bools.quick_menu_show_save_content_dir_overrides && !settings->bools.kiosk_mode_enable) { menu_entries_append_enum(info->list, @@ -6930,7 +6934,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) count++; } - if (settings->bools.quick_menu_show_save_game_overrides + if (settings->bools.quick_menu_show_save_game_overrides && !settings->bools.kiosk_mode_enable) { menu_entries_append_enum(info->list, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 4fb276be24..40f65a60a2 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -2468,7 +2468,16 @@ static bool setting_append_list( &subgroup_info, parent_group); settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); - +#ifdef HAVE_QT + CONFIG_ACTION( + list, list_info, + MENU_ENUM_LABEL_SHOW_WIMP, + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + &group_info, + &subgroup_info, + parent_group); + menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_UI_COMPANION_TOGGLE); +#endif #if !defined(IOS) /* Apple rejects iOS apps that let you forcibly quit them. */ CONFIG_ACTION( @@ -3497,7 +3506,7 @@ static bool setting_append_list( case SETTINGS_LIST_CHEAT_SEARCH: if ( ! cheat_manager_state.cheats ) break ; - + START_GROUP(list, list_info, &group_info, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_SETTINGS), parent_group); parent_group = msg_hash_to_str(MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS); @@ -3764,9 +3773,9 @@ static bool setting_append_list( general_write_handler, general_read_handler, SD_FLAG_NONE); - - - CONFIG_BOOL( + + + CONFIG_BOOL( list, list_info, &settings->bools.crt_switch_resolution, MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION, @@ -3780,18 +3789,18 @@ static bool setting_append_list( general_write_handler, general_read_handler, SD_FLAG_ADVANCED - ); - + ); + CONFIG_UINT( - list, list_info, - &settings->uints.crt_switch_resolution_super, - MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, - MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, - crt_switch_resolution_super, - &group_info, - &subgroup_info, - parent_group, - general_write_handler, + list, list_info, + &settings->uints.crt_switch_resolution_super, + MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, + MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, + crt_switch_resolution_super, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); diff --git a/msg_hash.h b/msg_hash.h index 8857983952..c00d899ca2 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1496,6 +1496,9 @@ enum msg_hash_enums MENU_LABEL(BUILDBOT_ASSETS_URL), MENU_LABEL(CORE_SET_SUPPORTS_NO_CONTENT_ENABLE), MENU_LABEL(CLOSE_CONTENT), +#ifdef HAVE_QT + MENU_LABEL(SHOW_WIMP), +#endif MENU_LABEL(QUIT_RETROARCH), MENU_LABEL(SHUTDOWN), MENU_LABEL(REBOOT), From d2e4832ebe2cbbc8aa9dba887e05d9d27d76bf16 Mon Sep 17 00:00:00 2001 From: alfrix Date: Fri, 17 Aug 2018 20:43:08 -0300 Subject: [PATCH 086/182] QT fix focus (bparker) --- ui/drivers/ui_qt.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index 067cf7b661..d410aca90f 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -607,6 +607,8 @@ static void ui_companion_qt_toggle(void *data, bool force) #endif if (settings->bools.ui_companion_toggle || force) { + win_handle->qtWindow->activateWindow(); + win_handle->qtWindow->raise(); video_driver_show_mouse(); win_handle->qtWindow->show(); From b915fd095de639e85f047fa22fb5458955b24906 Mon Sep 17 00:00:00 2001 From: alfrix Date: Sat, 18 Aug 2018 15:14:41 -0300 Subject: [PATCH 087/182] Fix focus for windows platforms (Tatsuya) --- ui/drivers/ui_qt.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index d410aca90f..e17954bf5a 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -607,6 +607,9 @@ static void ui_companion_qt_toggle(void *data, bool force) #endif if (settings->bools.ui_companion_toggle || force) { + if (settings->bools.video_fullscreen) + command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL); + win_handle->qtWindow->activateWindow(); win_handle->qtWindow->raise(); video_driver_show_mouse(); From 70d045818083762220e3f18caf474b11ece51655 Mon Sep 17 00:00:00 2001 From: alfrix Date: Sat, 18 Aug 2018 17:43:29 -0300 Subject: [PATCH 088/182] Add sublabel for 'Show desktop ui' --- intl/msg_hash_es.h | 4 ++++ intl/msg_hash_us.h | 4 ++++ menu/cbs/menu_cbs_sublabel.c | 9 ++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 624674b829..aa35a784ed 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -6421,6 +6421,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_WIMP, "Mostrar intefaz de escritorio" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_WIMP, + "Abre la interfaz de escritorio si fue cerrada" + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 6cfc4fb91c..ddc55482b6 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3843,6 +3843,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_WIMP, "Show Desktop UI" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_WIMP, + "Open the desktop UI if it was closed" + ) #endif MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, "Don't show this again") diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index d9fea4d60f..25ef29af8a 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -461,7 +461,9 @@ default_sublabel_macro(action_bind_sublabel_midi_output, default_sublabel_macro(action_bind_sublabel_midi_volume, MENU_ENUM_SUBLABEL_MIDI_VOLUME) default_sublabel_macro(action_bind_sublabel_onscreen_overlay_settings_list, MENU_ENUM_SUBLABEL_ONSCREEN_OVERLAY_SETTINGS) default_sublabel_macro(action_bind_sublabel_onscreen_notifications_settings_list, MENU_ENUM_SUBLABEL_ONSCREEN_NOTIFICATIONS_SETTINGS) - +#ifdef HAVE_QT +default_sublabel_macro(action_bind_sublabel_show_wimp, MENU_ENUM_SUBLABEL_SHOW_WIMP) +#endif static int action_bind_sublabel_cheevos_entry( file_list_t *list, @@ -1942,6 +1944,11 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_onscreen_notifications_settings_list); break; +#ifdef HAVE_QT + case MENU_ENUM_LABEL_SHOW_WIMP: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_show_wimp); + break; +#endif default: case MSG_UNKNOWN: return -1; From 380cd7ac53070856a8f303d9bb80582f17c2281d Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 17:39:37 -0400 Subject: [PATCH 089/182] Qt: add move up/down button for shader passes --- intl/msg_hash_ja.h | 4 + intl/msg_hash_us.h | 4 + msg_hash.h | 2 + ui/drivers/qt/shaderparamsdialog.cpp | 121 ++++++++++++++++++++++++++- ui/drivers/qt/shaderparamsdialog.h | 2 + ui/drivers/qt/ui_qt_window.cpp | 2 - 6 files changed, 131 insertions(+), 4 deletions(-) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 33ce9f1920..a8e823afb7 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3756,3 +3756,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT_CONTRIBUTORS, "作成者") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, "現在のシェーダー") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_DOWN, + "下へ移動") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_UP, + "上へ移動") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index ae6b760e09..729bc127de 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -4258,3 +4258,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT_CONTRIBUTORS, "Contributors") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, "Current shader") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_DOWN, + "Move Down") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_UP, + "Move Up") diff --git a/msg_hash.h b/msg_hash.h index 8857983952..de082a40af 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1980,6 +1980,8 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED, MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, + MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_DOWN, + MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_UP, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index c51bef5def..fbd48501b7 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "shaderparamsdialog.h" #include "../ui_qt.h" @@ -281,6 +282,98 @@ void ShaderParamsDialog::onScaleComboBoxIndexChanged(int) } } +void ShaderParamsDialog::onShaderPassMoveDownClicked() +{ + QPushButton *button = qobject_cast(sender()); + QVariant passVariant; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + int pass = 0; + bool ok = false; + + getShaders(&menu_shader, &video_shader); + + if (!button) + return; + + passVariant = button->property("pass"); + + if (!passVariant.isValid()) + return; + + pass = passVariant.toInt(&ok); + + if (!ok) + return; + + if (pass < 0) + return; + + if (video_shader) + { + if (pass >= static_cast(video_shader->passes) - 1) + return; + + std::swap(video_shader->pass[pass], video_shader->pass[pass + 1]); + } + + if (menu_shader) + { + if (pass >= static_cast(menu_shader->passes) - 1) + return; + + std::swap(menu_shader->pass[pass], menu_shader->pass[pass + 1]); + } + + command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); +} + +void ShaderParamsDialog::onShaderPassMoveUpClicked() +{ + QPushButton *button = qobject_cast(sender()); + QVariant passVariant; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + int pass = 0; + bool ok = false; + + getShaders(&menu_shader, &video_shader); + + if (!button) + return; + + passVariant = button->property("pass"); + + if (!passVariant.isValid()) + return; + + pass = passVariant.toInt(&ok); + + if (!ok) + return; + + if (pass <= 0) + return; + + if (video_shader) + { + if (pass > static_cast(video_shader->passes) - 1) + return; + + std::swap(video_shader->pass[pass - 1], video_shader->pass[pass]); + } + + if (menu_shader) + { + if (pass > static_cast(menu_shader->passes) - 1) + return; + + std::swap(menu_shader->pass[pass - 1], menu_shader->pass[pass]); + } + + command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); +} + void ShaderParamsDialog::reload() { struct video_shader *menu_shader = NULL; @@ -325,11 +418,29 @@ void ShaderParamsDialog::reload() QHBoxLayout *filterScaleHBoxLayout = NULL; QComboBox *filterComboBox = new QComboBox(); QComboBox *scaleComboBox = new QComboBox(); + QPushButton *moveDownButton = NULL; + QPushButton *moveUpButton = NULL; unsigned j = 0; filterComboBox->setProperty("pass", i); scaleComboBox->setProperty("pass", i); + /* Can't move down if we're already at the bottom. */ + if (i < static_cast(video_shader->passes) - 1) + { + moveDownButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_DOWN)); + moveDownButton->setProperty("pass", i); + connect(moveDownButton, SIGNAL(clicked()), this, SLOT(onShaderPassMoveDownClicked())); + } + + /* Can't move up if we're already at the top. */ + if (i > 0) + { + moveUpButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_UP)); + moveUpButton->setProperty("pass", i); + connect(moveUpButton, SIGNAL(clicked()), this, SLOT(onShaderPassMoveUpClicked())); + } + for (;;) { QString filterLabel = getFilterLabel(j); @@ -371,11 +482,17 @@ void ShaderParamsDialog::reload() m_layout->addWidget(groupBox); filterScaleHBoxLayout = new QHBoxLayout(); - filterScaleHBoxLayout->addWidget(new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FILTER))); + filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FILTER)) + ":")); filterScaleHBoxLayout->addWidget(filterComboBox); - filterScaleHBoxLayout->addWidget(new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCALE))); + filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCALE)) + ":")); filterScaleHBoxLayout->addWidget(scaleComboBox); + if (moveUpButton) + filterScaleHBoxLayout->addWidget(moveUpButton); + + if (moveDownButton) + filterScaleHBoxLayout->addWidget(moveDownButton); + form->addRow("", filterScaleHBoxLayout); for (j = 0; j < video_shader->num_parameters; j++) diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h index 5fb5376862..8bd7ed8f3c 100644 --- a/ui/drivers/qt/shaderparamsdialog.h +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -27,6 +27,8 @@ private slots: void onShaderParamDoubleSpinBoxValueChanged(double value); void onFilterComboBoxIndexChanged(int index); void onScaleComboBoxIndexChanged(int index); + void onShaderPassMoveDownClicked(); + void onShaderPassMoveUpClicked(); private: QString getFilterLabel(unsigned filter); void addShaderParam(struct video_shader_parameter *param, int parameter, QFormLayout *form); diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index d9c25546c5..7134bcc2c2 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -223,7 +223,6 @@ CoreInfoWidget::CoreInfoWidget(CoreInfoLabel *label, QWidget *parent) : ,m_label(label) ,m_scrollArea(new QScrollArea(this)) { - //m_scrollArea->setFrameShape(QFrame::NoFrame); m_scrollArea->setWidgetResizable(true); m_scrollArea->setWidget(m_label); } @@ -601,7 +600,6 @@ void MainWindow::onGridItemClicked(ThumbnailWidget *widget) if (m_currentGridWidget) { m_currentGridWidget->setObjectName("thumbnailWidget"); - //m_currentGridWidget->setFrameStyle(QFrame::Plain); m_currentGridWidget->style()->unpolish(m_currentGridWidget); m_currentGridWidget->style()->polish(m_currentGridWidget); } From c00fd41b93e4f83d0720bf9cdca6f935eed816bd Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 19:07:58 -0400 Subject: [PATCH 090/182] Qt: style fixup for filter/scale/move shader options --- intl/msg_hash_ja.h | 4 ++-- intl/msg_hash_us.h | 4 ++-- msg_hash.h | 4 ++-- ui/drivers/qt/shaderparamsdialog.cpp | 27 +++++++++++++++++---------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index a8e823afb7..d4c8627c33 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3756,7 +3756,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT_CONTRIBUTORS, "作成者") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, "現在のシェーダー") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_DOWN, +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, "下へ移動") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_UP, +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, "上へ移動") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 729bc127de..c1a98f01ac 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -4258,7 +4258,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT_CONTRIBUTORS, "Contributors") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, "Current shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_DOWN, +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, "Move Down") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_UP, +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, "Move Up") diff --git a/msg_hash.h b/msg_hash.h index de082a40af..1c7837abf9 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1980,8 +1980,8 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED, MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, - MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_DOWN, - MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_UP, + MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, + MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index fbd48501b7..23f2fc8c95 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "shaderparamsdialog.h" #include "../ui_qt.h" @@ -418,28 +419,32 @@ void ShaderParamsDialog::reload() QHBoxLayout *filterScaleHBoxLayout = NULL; QComboBox *filterComboBox = new QComboBox(); QComboBox *scaleComboBox = new QComboBox(); - QPushButton *moveDownButton = NULL; - QPushButton *moveUpButton = NULL; + QToolButton *moveDownButton = NULL; + QToolButton *moveUpButton = NULL; unsigned j = 0; filterComboBox->setProperty("pass", i); scaleComboBox->setProperty("pass", i); + moveDownButton = new QToolButton(); + moveDownButton->setText("↓"); + moveDownButton->setProperty("pass", i); + + moveUpButton = new QToolButton(); + moveUpButton->setText("↑"); + moveUpButton->setProperty("pass", i); + /* Can't move down if we're already at the bottom. */ if (i < static_cast(video_shader->passes) - 1) - { - moveDownButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_DOWN)); - moveDownButton->setProperty("pass", i); connect(moveDownButton, SIGNAL(clicked()), this, SLOT(onShaderPassMoveDownClicked())); - } + else + moveDownButton->setDisabled(true); /* Can't move up if we're already at the top. */ if (i > 0) - { - moveUpButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_MOVE_UP)); - moveUpButton->setProperty("pass", i); connect(moveUpButton, SIGNAL(clicked()), this, SLOT(onShaderPassMoveUpClicked())); - } + else + moveUpButton->setDisabled(true); for (;;) { @@ -482,10 +487,12 @@ void ShaderParamsDialog::reload() m_layout->addWidget(groupBox); filterScaleHBoxLayout = new QHBoxLayout(); + filterScaleHBoxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Preferred)); filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FILTER)) + ":")); filterScaleHBoxLayout->addWidget(filterComboBox); filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCALE)) + ":")); filterScaleHBoxLayout->addWidget(scaleComboBox); + filterScaleHBoxLayout->addSpacerItem(new QSpacerItem(20, 0, QSizePolicy::Preferred, QSizePolicy::Preferred)); if (moveUpButton) filterScaleHBoxLayout->addWidget(moveUpButton); From e0d99d7da234587a6fb45e683e381feb6c37ca80 Mon Sep 17 00:00:00 2001 From: alfrix Date: Sat, 18 Aug 2018 22:22:40 -0300 Subject: [PATCH 091/182] Change UI to menu --- intl/msg_hash_es.h | 4 ++-- intl/msg_hash_us.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index aa35a784ed..d90679a1cf 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -6419,11 +6419,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_WIMP, - "Mostrar intefaz de escritorio" + "Mostrar el menú de escritorio" ) MSG_HASH( MENU_ENUM_SUBLABEL_SHOW_WIMP, - "Abre la interfaz de escritorio si fue cerrada" + "Abre el menú de escritorio si fue cerrado" ) #endif MSG_HASH( diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index ddc55482b6..6413c47bbb 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3841,11 +3841,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, "Finally, the content must match existing databases from here. If it is still not working, consider submitting a bug report.") MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_WIMP, - "Show Desktop UI" + "Show Desktop Menu" ) MSG_HASH( MENU_ENUM_SUBLABEL_SHOW_WIMP, - "Open the desktop UI if it was closed" + "Opens the desktop menu if it was closed" ) #endif MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, From 7755c9ae5559d4abd9d63ccdcc48dd16a9606431 Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Sat, 18 Aug 2018 21:21:56 -0500 Subject: [PATCH 092/182] discord: removed the icon warning and uncommented the necessary line --- discord/discord.c | 36 +----------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/discord/discord.c b/discord/discord.c index 364f145fe5..25e6375f47 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -131,41 +131,7 @@ void discord_update(enum discord_presence presence) RARCH_LOG("[Discord] current core: %s\n", system_name); RARCH_LOG("[Discord] current content: %s\n", label); #endif - /* - At the present time, there is no consistent or clean way to present what platform - or core the user is playing on/with. If we were to present the platform as an icon, - some cores have multiple platforms, such as Dolphin with the GC or Wii, or blueMSX - with the MSX or MSX2. The libretro API has no way of determining what platform a - selected content is associated with; it only knows what core it's playing under. - The platform is determined by the core itself during initialization, not viewable - by the libretro API. A solution to this problem would be associating the content - with the first platform available in the core's information file, but that solution - doesn't work when someone sees another users playing Super Mario Galaxy with a - GameCube icon. It's not good enough. Another solution would be exposing what - platform is associated with inside the core itself, visible through the libretro - API, but this would require updating every libretro core to support this feature, - and the support would be too slow and limited for it to really work as a solution. - - If we were to present the core as an icon, there are a few options available, and - none of them are desirable either. If we were to provide an icon for each core based - on that core's logo or name, then we'd need new assets for every single libretro - core available, AND each asset would need to be consistent with each other, in a - similar vein to the XMB themes of RetroArch, which would be another massive - undertaking. If we were to provide an icon for each core based on that core's - platform, then we have the same issue as earlier, except this time we're additionally - limited by the amount of assets a Discord RPC application is allowed to have: 150. - There are currently 173 core information files available within RetroArch, which goes - over that number by a bit. Now if that were determined by platform instead of core, - that number goes significantly down as there are many cores with multiple platforms, - but then we have the issue as described earlier. - - Because of this dilemma, for now the provided icon for the In-Game status will be the - standard/default "core" icon, at least we can come up with a solution that's clean - and consistent. When such a time presents itself, the below line will be uncommented. - */ - - //discord_presence.largeImageKey = system_name; - discord_presence.largeImageKey = "core"; + discord_presence.largeImageKey = system_name; if (core_info->display_name) discord_presence.largeImageText = core_info->display_name; From b0146abd11609e142ff952be399342781dd48d4c Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 23:08:55 -0400 Subject: [PATCH 093/182] add fullpath and use_thread parameters to take_screenshot() --- cheevos/cheevos.c | 4 +- command.c | 2 +- tasks/task_save.c | 2 +- tasks/task_screenshot.c | 135 +++++++++++++++++++++++----------------- tasks/tasks_internal.h | 2 +- 5 files changed, 84 insertions(+), 61 deletions(-) diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index d65ed9ec32..0e21e3687a 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -1674,7 +1674,7 @@ static void cheevos_test_cheevo_set(const cheevoset_t *set) shotname[sizeof(shotname) - 1] = '\0'; if (take_screenshot(shotname, true, - video_driver_cached_frame_has_valid_framebuffer())) + video_driver_cached_frame_has_valid_framebuffer(), false, true)) CHEEVOS_LOG("[CHEEVOS]: got a screenshot for cheevo %u\n", cheevo->id); else CHEEVOS_LOG("[CHEEVOS]: failed to get screenshot for cheevo %u\n", cheevo->id); @@ -2080,7 +2080,7 @@ void cheevos_populate_menu(void *data) cheevo_t *cheevo = cheevos_locals.core.cheevos; end = cheevo + cheevos_locals.core.count; - if(settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable + if(settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable && cheevos_loaded) { if (!cheevos_hardcore_paused) diff --git a/command.c b/command.c index 55b2cf94e6..7cb6a22d37 100644 --- a/command.c +++ b/command.c @@ -1954,7 +1954,7 @@ bool command_event(enum event_command cmd, void *data) break; case CMD_EVENT_TAKE_SCREENSHOT: if (!take_screenshot(path_get(RARCH_PATH_BASENAME), false, - video_driver_cached_frame_has_valid_framebuffer())) + video_driver_cached_frame_has_valid_framebuffer(), false, true)) return false; break; case CMD_EVENT_UNLOAD_CORE: diff --git a/tasks/task_save.c b/tasks/task_save.c index 556da1fde0..1b5d93be4e 100644 --- a/tasks/task_save.c +++ b/tasks/task_save.c @@ -1010,7 +1010,7 @@ static void save_state_cb(void *task_data, char *path = strdup(state->path); if (state->thumbnail_enable) - take_screenshot(path, true, state->has_valid_framebuffer); + take_screenshot(path, true, state->has_valid_framebuffer, false, true); free(path); } diff --git a/tasks/task_screenshot.c b/tasks/task_screenshot.c index 42cc5d8d72..80c3b90cee 100644 --- a/tasks/task_screenshot.c +++ b/tasks/task_screenshot.c @@ -70,39 +70,17 @@ struct screenshot_task_state uint8_t *out_buffer; const void *frame; char filename[PATH_MAX_LENGTH]; - char shotname[256]; void *userbuf; struct scaler_ctx scaler; }; -/** - * task_screenshot_handler: - * @task : the task being worked on - * - * Saves a screenshot to disk. - **/ -static void task_screenshot_handler(retro_task_t *task) +static bool screenshot_dump_direct(screenshot_task_state_t *state) { + struct scaler_ctx *scaler = (struct scaler_ctx*)&state->scaler; + bool ret = false; #ifdef HAVE_RBMP enum rbmp_source_type bmp_type = RBMP_SOURCE_TYPE_DONT_CARE; -#endif - screenshot_task_state_t *state = (screenshot_task_state_t*)task->state; - struct scaler_ctx *scaler = (struct scaler_ctx*)&state->scaler; - bool ret = false; - - if (task_get_progress(task) == 100) - { - task_set_finished(task, true); - - if (state->userbuf) - free(state->userbuf); - - free(state); - return; - } - -#ifdef HAVE_RBMP - (void)bmp_type; + (void)bmp_type; #endif #if defined(HAVE_RPNG) @@ -146,6 +124,33 @@ static void task_screenshot_handler(retro_task_t *task) bmp_type); #endif + return ret; +} + +/** + * task_screenshot_handler: + * @task : the task being worked on + * + * Saves a screenshot to disk. + **/ +static void task_screenshot_handler(retro_task_t *task) +{ + screenshot_task_state_t *state = (screenshot_task_state_t*)task->state; + bool ret = false; + + if (task_get_progress(task) == 100) + { + task_set_finished(task, true); + + if (state->userbuf) + free(state->userbuf); + + free(state); + return; + } + + ret = screenshot_dump_direct(state); + #ifdef HAVE_IMAGEVIEWER if ( ret && !state->silence && @@ -178,7 +183,9 @@ static bool screenshot_dump( int pitch, bool bgr24, void *userbuf, bool savestate, bool is_idle, - bool is_paused) + bool is_paused, + bool fullpath, + bool use_thread) { char screenshot_path[PATH_MAX_LENGTH]; uint8_t *buf = NULL; @@ -187,14 +194,22 @@ static bool screenshot_dump( screenshot_task_state_t *state = (screenshot_task_state_t*) calloc(1, sizeof(*state)); const char *screenshot_dir = settings->paths.directory_screenshot; + char shotname[256]; + shotname[0] = '\0'; screenshot_path[0] = '\0'; - if (string_is_empty(screenshot_dir) || settings->bools.screenshots_in_content_dir) + /* If fullpath is true, name_base already contains a static path + filename to save the screenshot to. */ + if (fullpath) + strlcpy(state->filename, name_base, sizeof(state->filename)); + else { - fill_pathname_basedir(screenshot_path, name_base, - sizeof(screenshot_path)); - screenshot_dir = screenshot_path; + if (string_is_empty(screenshot_dir) || settings->bools.screenshots_in_content_dir) + { + fill_pathname_basedir(screenshot_path, name_base, + sizeof(screenshot_path)); + screenshot_dir = screenshot_path; + } } state->is_idle = is_idle; @@ -209,20 +224,23 @@ static bool screenshot_dump( state->history_list_enable = settings->bools.history_list_enable; state->pixel_format_type = video_driver_get_pixel_format(); - if (savestate) - snprintf(state->filename, - sizeof(state->filename), "%s.png", name_base); - else + if (!fullpath) { - if (settings->bools.auto_screenshot_filename) - fill_str_dated_filename(state->shotname, path_basename(name_base), - IMG_EXT, sizeof(state->shotname)); + if (savestate) + snprintf(state->filename, + sizeof(state->filename), "%s.png", name_base); else - snprintf(state->shotname, sizeof(state->shotname), - "%s.png", path_basename(name_base)); + { + if (settings->bools.auto_screenshot_filename) + fill_str_dated_filename(shotname, path_basename(name_base), + IMG_EXT, sizeof(shotname)); + else + snprintf(shotname, sizeof(shotname), + "%s.png", path_basename(name_base)); - fill_pathname_join(state->filename, screenshot_dir, - state->shotname, sizeof(state->filename)); + fill_pathname_join(state->filename, screenshot_dir, + shotname, sizeof(state->filename)); + } } #if defined(HAVE_RPNG) @@ -241,17 +259,22 @@ static bool screenshot_dump( task->state = state; task->handler = task_screenshot_handler; - if (!savestate) - task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); + if (use_thread) + return screenshot_dump_direct(state); + else + { + if (!savestate) + task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); - task_queue_push(task); + task_queue_push(task); + } return true; } #if !defined(VITA) static bool take_screenshot_viewport(const char *name_base, bool savestate, - bool is_idle, bool is_paused) + bool is_idle, bool is_paused, bool fullpath, bool use_thread) { struct video_viewport vp; uint8_t *buffer = NULL; @@ -280,7 +303,7 @@ static bool take_screenshot_viewport(const char *name_base, bool savestate, /* Data read from viewport is in bottom-up order, suitable for BMP. */ if (!screenshot_dump(name_base, buffer, vp.width, vp.height, - vp.width * 3, true, buffer, savestate, is_idle, is_paused)) + vp.width * 3, true, buffer, savestate, is_idle, is_paused, fullpath, use_thread)) goto error; return true; @@ -293,7 +316,7 @@ error: #endif static bool take_screenshot_raw(const char *name_base, void *userbuf, - bool savestate, bool is_idle, bool is_paused) + bool savestate, bool is_idle, bool is_paused, bool fullpath, bool use_thread) { size_t pitch; unsigned width, height; @@ -306,14 +329,14 @@ static bool take_screenshot_raw(const char *name_base, void *userbuf, */ if (!screenshot_dump(name_base, (const uint8_t*)data + (height - 1) * pitch, - width, height, (int)(-pitch), false, userbuf, savestate, is_idle, is_paused)) + width, height, (int)(-pitch), false, userbuf, savestate, is_idle, is_paused, fullpath, use_thread)) return false; return true; } static bool take_screenshot_choice(const char *name_base, bool savestate, - bool is_paused, bool is_idle, bool has_valid_framebuffer) + bool is_paused, bool is_idle, bool has_valid_framebuffer, bool fullpath, bool use_thread) { size_t old_pitch; unsigned old_width, old_height; @@ -335,14 +358,14 @@ static bool take_screenshot_choice(const char *name_base, bool savestate, if (!is_idle) video_driver_cached_frame(); #if defined(VITA) - return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused); + return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused, fullpath, use_thread); #else - return take_screenshot_viewport(name_base, savestate, is_idle, is_paused); + return take_screenshot_viewport(name_base, savestate, is_idle, is_paused, fullpath, use_thread); #endif } if (!has_valid_framebuffer) - return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused); + return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused, fullpath, use_thread); if (!video_driver_supports_read_frame_raw()) return false; @@ -359,14 +382,14 @@ static bool take_screenshot_choice(const char *name_base, bool savestate, if (frame_data) { video_driver_set_cached_frame_ptr(frame_data); - if (take_screenshot_raw(name_base, frame_data, savestate, is_idle, is_paused)) + if (take_screenshot_raw(name_base, frame_data, savestate, is_idle, is_paused, fullpath, use_thread)) ret = true; } return ret; } -bool take_screenshot(const char *name_base, bool silence, bool has_valid_framebuffer) +bool take_screenshot(const char *name_base, bool silence, bool has_valid_framebuffer, bool fullpath, bool use_thread) { bool is_paused = false; bool is_idle = false; @@ -377,7 +400,7 @@ bool take_screenshot(const char *name_base, bool silence, bool has_valid_framebu runloop_get_status(&is_paused, &is_idle, &is_slowmotion, &is_perfcnt_enable); ret = take_screenshot_choice(name_base, silence, is_paused, is_idle, - has_valid_framebuffer); + has_valid_framebuffer, fullpath, use_thread); if (is_paused && !is_idle) video_driver_cached_frame(); diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h index fe9bd41122..a2632e4ac8 100644 --- a/tasks/tasks_internal.h +++ b/tasks/tasks_internal.h @@ -223,7 +223,7 @@ void task_file_load_handler(retro_task_t *task); bool task_audio_mixer_load_handler(retro_task_t *task); -bool take_screenshot(const char *path, bool silence, bool has_valid_framebuffer); +bool take_screenshot(const char *path, bool silence, bool has_valid_framebuffer, bool fullpath, bool use_thread); bool event_load_save_files(void); From b1dde87ce59d8bbbc045b6983e28ae386f362bad Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 23:09:40 -0400 Subject: [PATCH 094/182] add --max-frames-ss and --max-frames-ss-path parameters for taking a screenshot after max_frames is reached --- retroarch.c | 246 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 145 insertions(+), 101 deletions(-) diff --git a/retroarch.c b/retroarch.c index de1298a024..42c8fa24b6 100644 --- a/retroarch.c +++ b/retroarch.c @@ -165,7 +165,9 @@ enum RA_OPT_VERSION, RA_OPT_EOF_EXIT, RA_OPT_LOG_FILE, - RA_OPT_MAX_FRAMES + RA_OPT_MAX_FRAMES, + RA_OPT_MAX_FRAMES_SCREENSHOT, + RA_OPT_MAX_FRAMES_SCREENSHOT_PATH }; enum runloop_state @@ -187,86 +189,88 @@ typedef struct runloop_ctx_msg_info } runloop_ctx_msg_info_t; static jmp_buf error_sjlj_context; -static enum rarch_core_type current_core_type = CORE_TYPE_PLAIN; -static enum rarch_core_type explicit_current_core_type = CORE_TYPE_PLAIN; -static char error_string[255] = {0}; +static enum rarch_core_type current_core_type = CORE_TYPE_PLAIN; +static enum rarch_core_type explicit_current_core_type = CORE_TYPE_PLAIN; +static char error_string[255] = {0}; static char runtime_shader_preset[255] = {0}; #ifdef HAVE_THREAD_STORAGE static sthread_tls_t rarch_tls; -const void *MAGIC_POINTER = (void*)(uintptr_t)0x0DEFACED; +const void *MAGIC_POINTER = (void*)(uintptr_t)0x0DEFACED; #endif static retro_bits_t has_set_libretro_device; -static bool has_set_core = false; -static bool has_set_username = false; +static bool has_set_core = false; +static bool has_set_username = false; #ifdef HAVE_DISCORD -static bool discord_is_inited = false; +static bool discord_is_inited = false; #endif -static bool rarch_is_inited = false; -static bool rarch_error_on_init = false; -static bool rarch_block_config_read = false; -static bool rarch_force_fullscreen = false; -static bool has_set_verbosity = false; -static bool has_set_libretro = false; -static bool has_set_libretro_directory = false; -static bool has_set_save_path = false; -static bool has_set_state_path = false; -static bool has_set_netplay_mode = false; -static bool has_set_netplay_ip_address = false; -static bool has_set_netplay_ip_port = false; -static bool has_set_netplay_stateless_mode = false; -static bool has_set_netplay_check_frames = false; -static bool has_set_ups_pref = false; -static bool has_set_bps_pref = false; -static bool has_set_ips_pref = false; +static bool rarch_is_inited = false; +static bool rarch_error_on_init = false; +static bool rarch_block_config_read = false; +static bool rarch_force_fullscreen = false; +static bool has_set_verbosity = false; +static bool has_set_libretro = false; +static bool has_set_libretro_directory = false; +static bool has_set_save_path = false; +static bool has_set_state_path = false; +static bool has_set_netplay_mode = false; +static bool has_set_netplay_ip_address = false; +static bool has_set_netplay_ip_port = false; +static bool has_set_netplay_stateless_mode = false; +static bool has_set_netplay_check_frames = false; +static bool has_set_ups_pref = false; +static bool has_set_bps_pref = false; +static bool has_set_ips_pref = false; -static bool rarch_is_sram_load_disabled = false; -static bool rarch_is_sram_save_disabled = false; -static bool rarch_use_sram = false; -static bool rarch_ups_pref = false; -static bool rarch_bps_pref = false; -static bool rarch_ips_pref = false; -static bool rarch_patch_blocked = false; -static bool rarch_first_start = true; +static bool rarch_is_sram_load_disabled = false; +static bool rarch_is_sram_save_disabled = false; +static bool rarch_use_sram = false; +static bool rarch_ups_pref = false; +static bool rarch_bps_pref = false; +static bool rarch_ips_pref = false; +static bool rarch_patch_blocked = false; +static bool rarch_first_start = true; -static bool runloop_force_nonblock = false; -static bool runloop_paused = false; -static bool runloop_idle = false; -static bool runloop_exec = false; -static bool runloop_slowmotion = false; -static bool runloop_fastmotion = false; -static bool runloop_shutdown_initiated = false; -static bool runloop_core_shutdown_initiated = false; -static bool runloop_perfcnt_enable = false; -static bool runloop_overrides_active = false; -static bool runloop_remaps_core_active = false; -static bool runloop_remaps_game_active = false; -static bool runloop_remaps_content_dir_active = false; -static bool runloop_game_options_active = false; -static bool runloop_missing_bios = false; -static bool runloop_autosave = false; +static bool runloop_force_nonblock = false; +static bool runloop_paused = false; +static bool runloop_idle = false; +static bool runloop_exec = false; +static bool runloop_slowmotion = false; +static bool runloop_fastmotion = false; +static bool runloop_shutdown_initiated = false; +static bool runloop_core_shutdown_initiated = false; +static bool runloop_perfcnt_enable = false; +static bool runloop_overrides_active = false; +static bool runloop_remaps_core_active = false; +static bool runloop_remaps_game_active = false; +static bool runloop_remaps_content_dir_active = false; +static bool runloop_game_options_active = false; +static bool runloop_missing_bios = false; +static bool runloop_autosave = false; #ifdef HAVE_DYNAMIC -static bool core_set_on_cmdline = false; +static bool core_set_on_cmdline = false; #endif static rarch_system_info_t runloop_system; static struct retro_frame_time_callback runloop_frame_time; -static retro_keyboard_event_t runloop_key_event = NULL; -static retro_keyboard_event_t runloop_frontend_key_event = NULL; -static core_option_manager_t *runloop_core_options = NULL; +static retro_keyboard_event_t runloop_key_event = NULL; +static retro_keyboard_event_t runloop_frontend_key_event = NULL; +static core_option_manager_t *runloop_core_options = NULL; #ifdef HAVE_THREADS -static slock_t *_runloop_msg_queue_lock = NULL; +static slock_t *_runloop_msg_queue_lock = NULL; #endif -static msg_queue_t *runloop_msg_queue = NULL; +static msg_queue_t *runloop_msg_queue = NULL; -static unsigned runloop_pending_windowed_scale = 0; -static unsigned runloop_max_frames = 0; -static unsigned fastforward_after_frames = 0; +static unsigned runloop_pending_windowed_scale = 0; +static unsigned runloop_max_frames = 0; +static bool runloop_max_frames_screenshot = false; +static char runloop_max_frames_screenshot_path[PATH_MAX_LENGTH] = {0}; +static unsigned fastforward_after_frames = 0; -static retro_usec_t runloop_frame_time_last = 0; -static retro_time_t frame_limit_minimum_time = 0.0; -static retro_time_t frame_limit_last_time = 0.0; +static retro_usec_t runloop_frame_time_last = 0; +static retro_time_t frame_limit_minimum_time = 0.0; +static retro_time_t frame_limit_last_time = 0.0; extern bool input_driver_flushing_input; @@ -593,7 +597,11 @@ static void retroarch_print_help(const char *arg0) "Not relevant for all platforms."); puts(" --max-frames=NUMBER\n" " Runs for the specified number of frames, " - "then exits.\n"); + "then exits."); + puts(" --max-frames-ss\n" + " Takes a screenshot at the end of max-frames."); + puts(" --max-frames-ss-path=FILE\n" + " Path to save the screenshot to at the end of max-frames.\n"); } #define FFMPEG_RECORD_ARG "r:" @@ -629,48 +637,50 @@ static void retroarch_parse_input_and_config(int argc, char *argv[]) const struct option opts[] = { #ifdef HAVE_DYNAMIC - { "libretro", 1, NULL, 'L' }, + { "libretro", 1, NULL, 'L' }, #endif - { "menu", 0, NULL, RA_OPT_MENU }, - { "help", 0, NULL, 'h' }, - { "save", 1, NULL, 's' }, - { "fullscreen", 0, NULL, 'f' }, - { "record", 1, NULL, 'r' }, - { "recordconfig", 1, NULL, RA_OPT_RECORDCONFIG }, - { "size", 1, NULL, RA_OPT_SIZE }, - { "verbose", 0, NULL, 'v' }, - { "config", 1, NULL, 'c' }, - { "appendconfig", 1, NULL, RA_OPT_APPENDCONFIG }, - { "nodevice", 1, NULL, 'N' }, - { "dualanalog", 1, NULL, 'A' }, - { "device", 1, NULL, 'd' }, - { "savestate", 1, NULL, 'S' }, - { "bsvplay", 1, NULL, 'P' }, - { "bsvrecord", 1, NULL, 'R' }, - { "sram-mode", 1, NULL, 'M' }, + { "menu", 0, NULL, RA_OPT_MENU }, + { "help", 0, NULL, 'h' }, + { "save", 1, NULL, 's' }, + { "fullscreen", 0, NULL, 'f' }, + { "record", 1, NULL, 'r' }, + { "recordconfig", 1, NULL, RA_OPT_RECORDCONFIG }, + { "size", 1, NULL, RA_OPT_SIZE }, + { "verbose", 0, NULL, 'v' }, + { "config", 1, NULL, 'c' }, + { "appendconfig", 1, NULL, RA_OPT_APPENDCONFIG }, + { "nodevice", 1, NULL, 'N' }, + { "dualanalog", 1, NULL, 'A' }, + { "device", 1, NULL, 'd' }, + { "savestate", 1, NULL, 'S' }, + { "bsvplay", 1, NULL, 'P' }, + { "bsvrecord", 1, NULL, 'R' }, + { "sram-mode", 1, NULL, 'M' }, #ifdef HAVE_NETWORKING - { "host", 0, NULL, 'H' }, - { "connect", 1, NULL, 'C' }, - { "stateless", 0, NULL, RA_OPT_STATELESS }, - { "check-frames", 1, NULL, RA_OPT_CHECK_FRAMES }, - { "port", 1, NULL, RA_OPT_PORT }, + { "host", 0, NULL, 'H' }, + { "connect", 1, NULL, 'C' }, + { "stateless", 0, NULL, RA_OPT_STATELESS }, + { "check-frames", 1, NULL, RA_OPT_CHECK_FRAMES }, + { "port", 1, NULL, RA_OPT_PORT }, #if defined(HAVE_NETWORK_CMD) - { "command", 1, NULL, RA_OPT_COMMAND }, + { "command", 1, NULL, RA_OPT_COMMAND }, #endif #endif - { "nick", 1, NULL, RA_OPT_NICK }, - { "ups", 1, NULL, 'U' }, - { "bps", 1, NULL, RA_OPT_BPS }, - { "ips", 1, NULL, RA_OPT_IPS }, - { "no-patch", 0, NULL, RA_OPT_NO_PATCH }, - { "detach", 0, NULL, 'D' }, - { "features", 0, NULL, RA_OPT_FEATURES }, - { "subsystem", 1, NULL, RA_OPT_SUBSYSTEM }, - { "max-frames", 1, NULL, RA_OPT_MAX_FRAMES }, - { "eof-exit", 0, NULL, RA_OPT_EOF_EXIT }, - { "version", 0, NULL, RA_OPT_VERSION }, + { "nick", 1, NULL, RA_OPT_NICK }, + { "ups", 1, NULL, 'U' }, + { "bps", 1, NULL, RA_OPT_BPS }, + { "ips", 1, NULL, RA_OPT_IPS }, + { "no-patch", 0, NULL, RA_OPT_NO_PATCH }, + { "detach", 0, NULL, 'D' }, + { "features", 0, NULL, RA_OPT_FEATURES }, + { "subsystem", 1, NULL, RA_OPT_SUBSYSTEM }, + { "max-frames", 1, NULL, RA_OPT_MAX_FRAMES }, + { "max-frames-ss", 0, NULL, RA_OPT_MAX_FRAMES_SCREENSHOT }, + { "max-frames-ss-path", 1, NULL, RA_OPT_MAX_FRAMES_SCREENSHOT_PATH }, + { "eof-exit", 0, NULL, RA_OPT_EOF_EXIT }, + { "version", 0, NULL, RA_OPT_VERSION }, #ifdef HAVE_FILE_LOGGER - { "log-file", 1, NULL, RA_OPT_LOG_FILE }, + { "log-file", 1, NULL, RA_OPT_LOG_FILE }, #endif { NULL, 0, NULL, 0 } }; @@ -1088,6 +1098,14 @@ static void retroarch_parse_input_and_config(int argc, char *argv[]) runloop_max_frames = (unsigned)strtoul(optarg, NULL, 10); break; + case RA_OPT_MAX_FRAMES_SCREENSHOT: + runloop_max_frames_screenshot = true; + break; + + case RA_OPT_MAX_FRAMES_SCREENSHOT_PATH: + strlcpy(runloop_max_frames_screenshot_path, optarg, sizeof(runloop_max_frames_screenshot_path)); + break; + case RA_OPT_SUBSYSTEM: path_set(RARCH_PATH_SUBSYSTEM, optarg); break; @@ -2631,6 +2649,32 @@ static enum runloop_state runloop_check_state( if (time_to_exit(trig_quit_key)) { + if ((runloop_max_frames != 0) && (frame_count >= runloop_max_frames)) + { + if (runloop_max_frames_screenshot) + { + const char *screenshot_path = NULL; + bool fullpath = false; + + if (string_is_empty(runloop_max_frames_screenshot_path)) + screenshot_path = path_get(RARCH_PATH_BASENAME); + else + { + fullpath = true; + screenshot_path = runloop_max_frames_screenshot_path; + } + + RARCH_LOG("Taking a screenshot before exiting...\n"); + + /* Take a screenshot before we exit. */ + if (!take_screenshot(screenshot_path, false, + video_driver_cached_frame_has_valid_framebuffer(), fullpath, false)) + { + RARCH_ERR("Could not take a screenshot before exiting.\n"); + } + } + } + if (runloop_exec) runloop_exec = false; @@ -2712,7 +2756,7 @@ static enum runloop_state runloop_check_state( } else { - if ( global->menu.prev_action == action && + if ( global->menu.prev_action == action && global->menu.noop_press_time < 200000) /* 250ms */ { global->menu.action_start_time = global->menu.prev_start_time ; @@ -3444,7 +3488,7 @@ int runloop_iterate(unsigned *sleep_ms) end: { retro_time_t to_sleep_ms; - + if (settings->bools.vrr_runloop_enable) { struct retro_system_av_info *av_info = @@ -3469,7 +3513,7 @@ int runloop_iterate(unsigned *sleep_ms) if (!settings->floats.fastforward_ratio && runloop_fastmotion) return 0; - frame_limit_minimum_time = + frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * (runloop_fastmotion ? settings->floats.fastforward_ratio : 1.0f))); } From a309400305b1bee49c3a4350c9e6ed62d7f9b6a5 Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Sun, 19 Aug 2018 15:54:56 +0200 Subject: [PATCH 095/182] name gridLayoutWidget --- ui/drivers/qt/ui_qt_window.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 7134bcc2c2..a29da9f841 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -370,6 +370,7 @@ MainWindow::MainWindow(QWidget *parent) : m_gridWidget->setLayout(new QVBoxLayout()); m_gridLayout = new FlowLayout(m_gridLayoutWidget); + m_gridLayoutWidget->setObjectName("gridLayoutWidget"); m_gridScrollArea->setAlignment(Qt::AlignCenter); m_gridScrollArea->setFrameShape(QFrame::NoFrame); From c051bae1bd015a5efd241905daa1d3ebf8bf992a Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Sun, 19 Aug 2018 15:56:19 +0200 Subject: [PATCH 096/182] Update ui_qt_themes.h --- ui/drivers/qt/ui_qt_themes.h | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/ui/drivers/qt/ui_qt_themes.h b/ui/drivers/qt/ui_qt_themes.h index 1844930c45..d92b163be0 100644 --- a/ui/drivers/qt/ui_qt_themes.h +++ b/ui/drivers/qt/ui_qt_themes.h @@ -34,22 +34,18 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( QTextEdit, LogTextEdit { background-color:rgb(25,25,25); } - QSpinBox, QCheckBox { + QSpinBox, QDoubleSpinBox, QCheckBox { background-color:rgb(25,25,25); } QCheckBox:checked, QCheckBox:unchecked { background-color:rgb(53,53,53); } - QDialog#shaderParamsDialog { + QWidget#shaderParamsWidget { background-color:rgb(25,25,25); } - QDialog#shaderParamsDialog QGroupBox, QDialog#shaderParamsDialog QGroupBox QLabel, - QDialog#shaderParamsDialog QGroupBox QSlider, QDialog#shaderParamsDialog QGroupBox QCheckBox:checked, - QDialog#shaderParamsDialog QGroupBox QCheckBox:unchecked { - background-color:rgb(53,53,53); - } QDialog#shaderParamsDialog QGroupBox { - border-top-left-radius: 0px; + background-color:rgb(53,53,53); + border-top-left-radius:0px; } QDialog#shaderParamsDialog QGroupBox::title { margin-left:0px; @@ -58,7 +54,7 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgb(53,53,53),stop:1 rgba(125,125,125,127)); border:1px solid rgba(25,25,25,75); border-top:1px solid rgba(175,175,175,50%); - border-bottom: none transparent; + border-bottom:none transparent; } QToolTip { color:white; @@ -224,7 +220,7 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( } QComboBox { min-height:20px; - padding:1px 18px 1px 3px; + padding:1px 6px 1px 6px; } QComboBox::focus { background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,50), stop: 1 rgba(100,100,100,25)); @@ -238,6 +234,7 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( } QComboBox::drop-down { background-color:transparent; + width:0px; } QComboBox::selected:on, QComboBox::selected:off { background-color:%1; @@ -262,6 +259,10 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( padding:1px 3px 1px 3px; outline:none; } + QPushButton::disabled, QToolButton::disabled { + color:grey; + background-color:rgb(25,25,25); + } QPushButton::focus, QToolButton::focus { background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,50), stop: 1 rgba(100,100,100,25)); border:1px solid %1; @@ -277,8 +278,8 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( border:1px solid %1; border-radius:4px; } - QPushButton[flat="true"] { - background-color: transparent; + QPushButton[flat=\"true\"] { + background-color:transparent; } QRadioButton::indicator { width:18px; @@ -428,7 +429,7 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( background-color:rgb(40,40,40); border:3px solid %1; } - QScrollArea QWidget { - background:rgb(25,25,25); + QWidget#gridLayoutWidget { + background-color:rgb(25,25,25); } )"); From 9e9fb5803e8e72217f342ddb8807402d5eccd90e Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Sun, 19 Aug 2018 16:00:19 +0200 Subject: [PATCH 097/182] Update ui_qt_themes.h --- ui/drivers/qt/ui_qt_themes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/drivers/qt/ui_qt_themes.h b/ui/drivers/qt/ui_qt_themes.h index d92b163be0..803cf8a37a 100644 --- a/ui/drivers/qt/ui_qt_themes.h +++ b/ui/drivers/qt/ui_qt_themes.h @@ -278,7 +278,7 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( border:1px solid %1; border-radius:4px; } - QPushButton[flat=\"true\"] { + QPushButton[flat="true"] { background-color:transparent; } QRadioButton::indicator { From 821ffc9962ff96bbdb942f88411f14185d46ad6a Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 19 Aug 2018 16:12:54 +0200 Subject: [PATCH 098/182] Clang scan-build error fix --- libretro-common/formats/png/rpng_encode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libretro-common/formats/png/rpng_encode.c b/libretro-common/formats/png/rpng_encode.c index 3500c3aaf4..42df8116aa 100644 --- a/libretro-common/formats/png/rpng_encode.c +++ b/libretro-common/formats/png/rpng_encode.c @@ -150,7 +150,10 @@ static unsigned count_sad(const uint8_t *data, size_t size) size_t i; unsigned cnt = 0; for (i = 0; i < size; i++) - cnt += abs((int8_t)data[i]); + { + if (data[i]) + cnt += abs((int8_t)data[i]); + } return cnt; } From f6dc3345e9df0142c7a9fef0369b1ee7133138b2 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 19 Aug 2018 11:05:25 -0400 Subject: [PATCH 099/182] Qt: use native path separators for folder scan from file browser, fixes #7084 --- ui/drivers/qt/ui_qt_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index a29da9f841..28c3afd91c 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -840,7 +840,7 @@ void MainWindow::onFileBrowserTreeContextMenuRequested(const QPoint&) QList actions; QScopedPointer scanAction; QDir dir; - QString currentDirString = m_dirModel->filePath(m_dirTree->currentIndex()); + QString currentDirString = QDir::toNativeSeparators(m_dirModel->filePath(m_dirTree->currentIndex())); settings_t *settings = config_get_ptr(); QByteArray dirArray; const char *fullpath = NULL; From d571bfaf176c3ac7617c3157fdad1ca8e47af3ef Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 19 Aug 2018 11:46:33 -0400 Subject: [PATCH 100/182] Qt: use native path separators for file browser content --- ui/drivers/qt/ui_qt_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 28c3afd91c..9e64b80a69 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -1399,7 +1399,7 @@ void MainWindow::selectBrowserDir(QString path) QString fileName = dirList.at(i); QTableWidgetItem *item = new QTableWidgetItem(fileName); QHash hash; - QString filePath(dir.absoluteFilePath(fileName)); + QString filePath(QDir::toNativeSeparators(dir.absoluteFilePath(fileName))); QFileInfo fileInfo(filePath); hash["path"] = filePath; From 5ba4103f6e72310d9375f0c6caa5ffa2252c18f2 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Sun, 19 Aug 2018 12:49:47 -0400 Subject: [PATCH 101/182] pkg: Add MAME 2003 Plus --- pkg/ctr/Makefile.cores | 8 ++++++++ pkg/ctr/assets/mame2003_plus.png | Bin 0 -> 1275 bytes pkg/ctr/assets/mame2003_plus_banner.png | Bin 0 -> 38848 bytes 3 files changed, 8 insertions(+) create mode 100644 pkg/ctr/assets/mame2003_plus.png create mode 100644 pkg/ctr/assets/mame2003_plus_banner.png diff --git a/pkg/ctr/Makefile.cores b/pkg/ctr/Makefile.cores index 8fabdb8bd7..391fe18045 100644 --- a/pkg/ctr/Makefile.cores +++ b/pkg/ctr/Makefile.cores @@ -139,6 +139,14 @@ else ifeq ($(LIBRETRO), mame2003) APP_BANNER = pkg/ctr/assets/mame2003_banner.png APP_BIG_TEXT_SECTION = 1 +else ifeq ($(LIBRETRO), mame2003_plus) + APP_TITLE = MAME-2003-PLUS + APP_PRODUCT_CODE = RARCH-MAME2003-PLUS + APP_UNIQUE_ID = 0xBAC22 + APP_ICON = pkg/ctr/assets/mame2003_plus.png + APP_BANNER = pkg/ctr/assets/mame2003_plus_banner.png + APP_BIG_TEXT_SECTION = 1 + else ifeq ($(LIBRETRO), mednafen_pce_fast) APP_TITLE = Mednafen/Beetle PCE FAST APP_AUTHOR = Ryphecha diff --git a/pkg/ctr/assets/mame2003_plus.png b/pkg/ctr/assets/mame2003_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..86509ec99998985126fb4dc30ece70dfb4140792 GIT binary patch literal 1275 zcmV3N)n2w7Na%BB1FZ-xMXW~<4GkHODB zpQG7oqI=p!|7Hl2=sbW?H88lmUMUlTD3pQ_L}4xWOikwtS(!|v`vZWgDv3*4L(3JR z@9SV5%k*E@Jz?E>9LHX*4gl!2dpP`X$U*4)I^O>M7QJ>a(|^&8vhGQg&eqCAeE)bj zf@vABrw%&Do!s>kZ=t4TU_2aU+;bf-aW5}weJ?$3mii*~|mkC70(m6rvxW@rhc1>JQCJ1IUnL3IrVYgDrojTL01Iof& z@p%xED8RCejkzZ=c1s?q1XulGc6(zHJQm=}8$#0*5I<{J+VVW{i`OX&ksdQGKF__6 z?_cBO>;eI0P#G(JrHoVp&kOF{K0PC&SQ+=YLZ)kSRDEV(FtV3EMmMS^M*lh+o5zdL%ea>T007aH@2vyWrO-45 z%$_~S$+E0_8GtlIQ9Pvhjr<>A_6&`x2~AUy_gz60plJ#kRr9wK&pELDL-QDaXb5@Q l0NbB@k3NNfXzRdZ#(z}=Xy*pYBSQcH002ovPDHLkV1hG7MlS#W literal 0 HcmV?d00001 diff --git a/pkg/ctr/assets/mame2003_plus_banner.png b/pkg/ctr/assets/mame2003_plus_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..6b73ffe5fddc478e18bde646a7cbce63e1df62b7 GIT binary patch literal 38848 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 Date: Sun, 19 Aug 2018 16:26:16 -0400 Subject: [PATCH 102/182] Qt: add load/save/remove/apply buttons to top of shaders dialog --- intl/msg_hash_ja.h | 14 ++ intl/msg_hash_us.h | 14 ++ msg_hash.h | 7 + ui/drivers/qt/shaderparamsdialog.cpp | 343 ++++++++++++++++++++++++++- ui/drivers/qt/shaderparamsdialog.h | 10 + 5 files changed, 382 insertions(+), 6 deletions(-) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index d4c8627c33..88adc933c0 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3760,3 +3760,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, "下へ移動") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, "上へ移動") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOAD, + "ロード") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SAVE, + "保存") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_REMOVE, + "取り除く") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_APPLY, + "適用") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, + "パスを追加") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, + "すべてのパスを取り除く") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, + "シェーダーパスはありません。") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 0815a52aaf..8bb57653c9 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -4270,3 +4270,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, "Move Down") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, "Move Up") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOAD, + "Load") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SAVE, + "Save") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_REMOVE, + "Remove") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_APPLY, + "Apply") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, + "Add Pass") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, + "Clear All Passes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, + "No shader passes.") diff --git a/msg_hash.h b/msg_hash.h index a696ee5ca0..5ea9620d1c 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1985,6 +1985,13 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, + MENU_ENUM_LABEL_VALUE_QT_LOAD, + MENU_ENUM_LABEL_VALUE_QT_SAVE, + MENU_ENUM_LABEL_VALUE_QT_REMOVE, + MENU_ENUM_LABEL_VALUE_QT_APPLY, + MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, + MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, + MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 23f2fc8c95..4d549ce309 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -11,18 +11,33 @@ #include #include #include +#include +#include #include "shaderparamsdialog.h" #include "../ui_qt.h" extern "C" { #include +#include +#include #include "../../../command.h" +#include "../../../configuration.h" +#include "../../../retroarch.h" +#include "../../../paths.h" #ifdef HAVE_MENU #include "../../../menu/menu_shader.h" #endif } +enum +{ + SHADER_PRESET_SAVE_CORE = 0, + SHADER_PRESET_SAVE_GAME, + SHADER_PRESET_SAVE_PARENT, + SHADER_PRESET_SAVE_NORMAL +}; + ShaderParamsDialog::ShaderParamsDialog(QWidget *parent) : QDialog(parent) ,m_layout(NULL) @@ -375,13 +390,265 @@ void ShaderParamsDialog::onShaderPassMoveUpClicked() command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); } +void ShaderParamsDialog::onShaderLoadPresetClicked() +{ +#ifdef HAVE_MENU + QString path; + QByteArray pathArray; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + const char *pathData = NULL; + settings_t *settings = config_get_ptr(); + enum rarch_shader_type type = RARCH_SHADER_NONE; + + if (!settings) + return; + + getShaders(&menu_shader, &video_shader); + + if (!menu_shader) + return; + + path = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), settings->paths.directory_video_shader); + + if (path.isEmpty()) + return; + + pathArray = path.toUtf8(); + pathData = pathArray.constData(); + + type = video_shader_parse_type(pathData, RARCH_SHADER_NONE); + + menu_shader_manager_set_preset(menu_shader, type, pathData); +#endif +} + +void ShaderParamsDialog::onShaderAddPassClicked() +{ +#ifdef HAVE_MENU + QString path; + QByteArray pathArray; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + struct video_shader_pass *shader_pass = NULL; + const char *pathData = NULL; + settings_t *settings = config_get_ptr(); + + if (!settings) + return; + + getShaders(&menu_shader, &video_shader); + + if (!menu_shader) + return; + + path = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), settings->paths.directory_video_shader); + + if (path.isEmpty()) + return; + + pathArray = path.toUtf8(); + pathData = pathArray.constData(); + + if (menu_shader->passes < GFX_MAX_SHADERS) + menu_shader_manager_increment_amount_passes(); + else + return; + + shader_pass = &menu_shader->pass[menu_shader->passes - 1]; + + if (!shader_pass) + return; + + strlcpy(shader_pass->source.path, pathData, sizeof(shader_pass->source.path)); + + video_shader_resolve_parameters(NULL, menu_shader); + + command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); +#endif +} + +void ShaderParamsDialog::onShaderSavePresetAsClicked() +{ +#ifdef HAVE_MENU + settings_t *settings = config_get_ptr(); + QString path; + QByteArray pathArray; + const char *pathData = NULL; + + path = QFileDialog::getSaveFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS), settings->paths.directory_video_shader); + + if (path.isEmpty()) + return; + + pathArray = path.toUtf8(); + pathData = pathArray.constData(); + + saveShaderPreset(pathData, SHADER_PRESET_SAVE_NORMAL); +#endif +} + +void ShaderParamsDialog::saveShaderPreset(const char *path, unsigned action_type) +{ + char directory[PATH_MAX_LENGTH]; + char file[PATH_MAX_LENGTH]; + char tmp[PATH_MAX_LENGTH]; + settings_t *settings = config_get_ptr(); + const char *core_name = NULL; + rarch_system_info_t *info = runloop_get_system_info(); + + directory[0] = file[0] = tmp[0] = '\0'; + + if (info) + core_name = info->info.library_name; + + if (!string_is_empty(core_name)) + { + fill_pathname_join( + tmp, + settings->paths.directory_video_shader, + "presets", + sizeof(tmp)); + fill_pathname_join( + directory, + tmp, + core_name, + sizeof(directory)); + } + + if (!filestream_exists(directory)) + path_mkdir(directory); + + switch (action_type) + { + case SHADER_PRESET_SAVE_CORE: + if (!string_is_empty(core_name)) + fill_pathname_join(file, directory, core_name, sizeof(file)); + break; + case SHADER_PRESET_SAVE_GAME: + { + const char *game_name = path_basename(path_get(RARCH_PATH_BASENAME)); + fill_pathname_join(file, directory, game_name, sizeof(file)); + break; + } + case SHADER_PRESET_SAVE_PARENT: + { + fill_pathname_parent_dir_name(tmp, path_get(RARCH_PATH_BASENAME), sizeof(tmp)); + fill_pathname_join(file, directory, tmp, sizeof(file)); + break; + } + case SHADER_PRESET_SAVE_NORMAL: + default: + if (!string_is_empty(path)) + strlcpy(file, path, sizeof(file)); + break; + } + + if (menu_shader_manager_save_preset(file, false, true)) + runloop_msg_queue_push( + msg_hash_to_str(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY), + 1, 100, true); + else + runloop_msg_queue_push( + msg_hash_to_str(MSG_ERROR_SAVING_SHADER_PRESET), + 1, 100, true); +} + +void ShaderParamsDialog::onShaderSaveCorePresetClicked() +{ + saveShaderPreset(NULL, SHADER_PRESET_SAVE_CORE); +} + +void ShaderParamsDialog::onShaderSaveParentPresetClicked() +{ + saveShaderPreset(NULL, SHADER_PRESET_SAVE_PARENT); +} + +void ShaderParamsDialog::onShaderSaveGamePresetClicked() +{ + saveShaderPreset(NULL, SHADER_PRESET_SAVE_GAME); +} + +void ShaderParamsDialog::onShaderClearAllPassesClicked() +{ +#ifdef HAVE_MENU + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + + getShaders(&menu_shader, &video_shader); + + if (!menu_shader) + return; + + while (menu_shader->passes > 0) + menu_shader_manager_decrement_amount_passes(); + + onShaderApplyClicked(); +#endif +} + +void ShaderParamsDialog::onShaderRemovePassClicked() +{ +#ifdef HAVE_MENU + QAction *action = qobject_cast(sender()); + QVariant passVariant; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + int pass = 0; + int i; + bool ok = false; + + getShaders(&menu_shader, &video_shader); + + if (!menu_shader || menu_shader->passes == 0 || !action) + return; + + passVariant = action->data(); + + if (!passVariant.isValid()) + return; + + pass = passVariant.toInt(&ok); + + if (!ok) + return; + + if (pass < 0 || pass > static_cast(menu_shader->passes)) + return; + + /* move selected pass to the bottom */ + for (i = pass; i < static_cast(menu_shader->passes) - 1; i++) + { + std::swap(menu_shader->pass[i], menu_shader->pass[i + 1]); + } + + menu_shader_manager_decrement_amount_passes(); + + onShaderApplyClicked(); +#endif +} + +void ShaderParamsDialog::onShaderApplyClicked() +{ + command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); +} + void ShaderParamsDialog::reload() { + QPushButton *loadButton = NULL; + QPushButton *saveButton = NULL; + QPushButton *removeButton = NULL; + QPushButton *applyButton = NULL; + QHBoxLayout *topButtonLayout = NULL; + QMenu *loadMenu = NULL; + QMenu *saveMenu = NULL; + QMenu *removeMenu = NULL; struct video_shader *menu_shader = NULL; struct video_shader *video_shader = NULL; const char *shader_path = NULL; int i; unsigned j; + bool hasPasses = false; getShaders(&menu_shader, &video_shader); @@ -409,6 +676,56 @@ void ShaderParamsDialog::reload() else setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); + loadButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_LOAD), this); + saveButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SAVE), this); + removeButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_REMOVE), this); + applyButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_APPLY), this); + + loadMenu = new QMenu(loadButton); + loadMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), this, SLOT(onShaderLoadPresetClicked())); + loadMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS), this, SLOT(onShaderAddPassClicked())); + + loadButton->setMenu(loadMenu); + + saveMenu = new QMenu(saveButton); + saveMenu->addAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS)) + "...", this, SLOT(onShaderSavePresetAsClicked())); + saveMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE), this, SLOT(onShaderSaveCorePresetClicked())); + saveMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT), this, SLOT(onShaderSaveParentPresetClicked())); + saveMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME), this, SLOT(onShaderSaveGamePresetClicked())); + + saveButton->setMenu(saveMenu); + + removeMenu = new QMenu(removeButton); + + /* When there are no passes, at least on first startup, it seems video_shader erroneously shows 1 pass, with an empty source file. + * So we use menu_shader instead for that. + */ + if (menu_shader) + { + for (i = 0; i < static_cast(menu_shader->passes); i++) + { + QFileInfo fileInfo(menu_shader->pass[i].source.path); + QString shaderBasename = fileInfo.completeBaseName(); + QAction *action = removeMenu->addAction(shaderBasename, this, SLOT(onShaderRemovePassClicked())); + + action->setData(i); + } + } + + removeMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES), this, SLOT(onShaderClearAllPassesClicked())); + + removeButton->setMenu(removeMenu); + + connect(applyButton, SIGNAL(clicked()), this, SLOT(onShaderApplyClicked())); + + topButtonLayout = new QHBoxLayout(); + topButtonLayout->addWidget(loadButton); + topButtonLayout->addWidget(saveButton); + topButtonLayout->addWidget(removeButton); + topButtonLayout->addWidget(applyButton); + + m_layout->addLayout(topButtonLayout); + /* NOTE: We assume that parameters are always grouped in order by the pass number, e.g., all parameters for pass 0 come first, then params for pass 1, etc. */ for (i = 0; i < static_cast(video_shader->passes); i++) { @@ -417,20 +734,26 @@ void ShaderParamsDialog::reload() QFileInfo fileInfo(video_shader->pass[i].source.path); QString shaderBasename = fileInfo.completeBaseName(); QHBoxLayout *filterScaleHBoxLayout = NULL; - QComboBox *filterComboBox = new QComboBox(); - QComboBox *scaleComboBox = new QComboBox(); + QComboBox *filterComboBox = new QComboBox(this); + QComboBox *scaleComboBox = new QComboBox(this); QToolButton *moveDownButton = NULL; QToolButton *moveUpButton = NULL; unsigned j = 0; + /* Sometimes video_shader shows 1 pass with no source file, when there are really 0 passes. */ + if (shaderBasename.isEmpty()) + continue; + + hasPasses = true; + filterComboBox->setProperty("pass", i); scaleComboBox->setProperty("pass", i); - moveDownButton = new QToolButton(); + moveDownButton = new QToolButton(this); moveDownButton->setText("↓"); moveDownButton->setProperty("pass", i); - moveUpButton = new QToolButton(); + moveUpButton = new QToolButton(this); moveUpButton->setText("↑"); moveUpButton->setProperty("pass", i); @@ -488,9 +811,9 @@ void ShaderParamsDialog::reload() filterScaleHBoxLayout = new QHBoxLayout(); filterScaleHBoxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Preferred)); - filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FILTER)) + ":")); + filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FILTER)) + ":", this)); filterScaleHBoxLayout->addWidget(filterComboBox); - filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCALE)) + ":")); + filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCALE)) + ":", this)); filterScaleHBoxLayout->addWidget(scaleComboBox); filterScaleHBoxLayout->addSpacerItem(new QSpacerItem(20, 0, QSizePolicy::Preferred, QSizePolicy::Preferred)); @@ -513,6 +836,14 @@ void ShaderParamsDialog::reload() } } + if (!hasPasses) + { + QLabel *noParamsLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES), this); + noParamsLabel->setAlignment(Qt::AlignCenter); + + m_layout->addWidget(noParamsLabel); + } + m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); end: diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h index 8bd7ed8f3c..5e2afdb9a2 100644 --- a/ui/drivers/qt/shaderparamsdialog.h +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -29,11 +29,21 @@ private slots: void onScaleComboBoxIndexChanged(int index); void onShaderPassMoveDownClicked(); void onShaderPassMoveUpClicked(); + void onShaderLoadPresetClicked(); + void onShaderAddPassClicked(); + void onShaderSavePresetAsClicked(); + void onShaderSaveCorePresetClicked(); + void onShaderSaveParentPresetClicked(); + void onShaderSaveGamePresetClicked(); + void onShaderClearAllPassesClicked(); + void onShaderRemovePassClicked(); + void onShaderApplyClicked(); private: QString getFilterLabel(unsigned filter); void addShaderParam(struct video_shader_parameter *param, int parameter, QFormLayout *form); void clearLayout(QLayout *layout); void getShaders(struct video_shader **menu_shader, struct video_shader **video_shader); + void saveShaderPreset(const char *path, unsigned action_type); QVBoxLayout *m_layout; protected: From 8380ad61f9595f4783a7efd2bf3ab2b76552fb40 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 19 Aug 2018 18:54:13 -0400 Subject: [PATCH 103/182] Qt: add missing paintEvent overrides for stylesheet correctness --- ui/drivers/qt/shaderparamsdialog.cpp | 14 +++++ ui/drivers/qt/shaderparamsdialog.h | 2 + ui/drivers/qt/ui_qt_window.cpp | 78 ++++++++++++++++++++++++++++ ui/drivers/qt/viewoptionsdialog.cpp | 13 +++++ ui/drivers/qt/viewoptionsdialog.h | 2 + ui/drivers/ui_qt.h | 10 ++++ 6 files changed, 119 insertions(+) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 4d549ce309..bfbf9bf532 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -1152,3 +1153,16 @@ void ShaderParamsDialog::onShaderParamDoubleSpinBoxValueChanged(double value) } } } + +void ShaderParamsDialog::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QDialog::paintEvent(event); +} diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h index 5e2afdb9a2..73c6f82423 100644 --- a/ui/drivers/qt/shaderparamsdialog.h +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -5,6 +5,7 @@ class QCloseEvent; class QResizeEvent; +class QPaintEvent; class QVBoxLayout; class QFormLayout; class QLayout; @@ -49,6 +50,7 @@ private: protected: void closeEvent(QCloseEvent *event); void resizeEvent(QResizeEvent *event); + void paintEvent(QPaintEvent *event); }; #endif diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 9e64b80a69..7d980f7093 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -191,6 +191,19 @@ void TreeView::selectionChanged(const QItemSelection &selected, const QItemSelec emit itemsSelected(list); } +void TreeView::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QTreeView::paintEvent(event); +} + TableWidget::TableWidget(QWidget *parent) : QTableWidget(parent) { @@ -212,12 +225,38 @@ void TableWidget::keyPressEvent(QKeyEvent *event) QTableWidget::keyPressEvent(event); } +void TableWidget::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QTableWidget::paintEvent(event); +} + CoreInfoLabel::CoreInfoLabel(QString text, QWidget *parent) : QLabel(text, parent) { setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); } +void CoreInfoLabel::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QLabel::paintEvent(event); +} + CoreInfoWidget::CoreInfoWidget(CoreInfoLabel *label, QWidget *parent) : QWidget(parent) ,m_label(label) @@ -238,6 +277,19 @@ void CoreInfoWidget::resizeEvent(QResizeEvent *event) m_scrollArea->resize(event->size()); } +void CoreInfoWidget::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QWidget::paintEvent(event); +} + LogTextEdit::LogTextEdit(QWidget *parent) : QPlainTextEdit(parent) { @@ -253,6 +305,19 @@ void LogTextEdit::appendMessage(const QString& text) verticalScrollBar()->setValue(verticalScrollBar()->maximum()); } +void LogTextEdit::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QPlainTextEdit::paintEvent(event); +} + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) ,m_loadCoreWindow(new LoadCoreWindow(this)) @@ -2947,6 +3012,19 @@ void MainWindow::onShowInfoMessage(QString msg) showMessageBox(msg, MainWindow::MSGBOX_TYPE_INFO, Qt::ApplicationModal, false); } +void MainWindow::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QMainWindow::paintEvent(event); +} + static void* ui_window_qt_init(void) { ui_window.qtWindow = new MainWindow(); diff --git a/ui/drivers/qt/viewoptionsdialog.cpp b/ui/drivers/qt/viewoptionsdialog.cpp index a293b01a00..fc265b6af0 100644 --- a/ui/drivers/qt/viewoptionsdialog.cpp +++ b/ui/drivers/qt/viewoptionsdialog.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "viewoptionsdialog.h" #include "../ui_qt.h" @@ -216,3 +217,15 @@ void ViewOptionsDialog::hideDialog() reject(); } +void ViewOptionsDialog::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QDialog::paintEvent(event); +} diff --git a/ui/drivers/qt/viewoptionsdialog.h b/ui/drivers/qt/viewoptionsdialog.h index 7b5c7c71fe..1ceb70f313 100644 --- a/ui/drivers/qt/viewoptionsdialog.h +++ b/ui/drivers/qt/viewoptionsdialog.h @@ -44,6 +44,8 @@ private: QCheckBox *m_suggestLoadedCoreFirstCheckBox; QSpinBox *m_allPlaylistsListMaxCountSpinBox; QSpinBox *m_allPlaylistsGridMaxCountSpinBox; +protected: + void paintEvent(QPaintEvent *event); }; #endif diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 0b8debb3b9..c04ae44173 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -153,6 +153,8 @@ signals: protected slots: void columnCountChanged(int oldCount, int newCount); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); +protected: + void paintEvent(QPaintEvent *event); }; class TableWidget : public QTableWidget @@ -165,6 +167,8 @@ signals: void deletePressed(); protected: void keyPressEvent(QKeyEvent *event); +protected: + void paintEvent(QPaintEvent *event); }; class AppHandler : public QObject @@ -186,6 +190,8 @@ class CoreInfoLabel : public QLabel Q_OBJECT public: CoreInfoLabel(QString text = QString(), QWidget *parent = 0); +protected: + void paintEvent(QPaintEvent *event); }; class CoreInfoWidget : public QWidget @@ -196,6 +202,7 @@ public: QSize sizeHint() const; protected: void resizeEvent(QResizeEvent *event); + void paintEvent(QPaintEvent *event); private: CoreInfoLabel *m_label; QScrollArea *m_scrollArea; @@ -208,6 +215,8 @@ public: LogTextEdit(QWidget *parent = 0); public slots: void appendMessage(const QString& text); +protected: + void paintEvent(QPaintEvent *event); }; class MainWindow : public QMainWindow @@ -450,6 +459,7 @@ private: protected: void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *event); + void paintEvent(QPaintEvent *event); }; Q_DECLARE_METATYPE(ThumbnailWidget) From 3ad54bc9ca970b315ce844f3f38c0c398d110430 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 19 Aug 2018 19:27:06 -0400 Subject: [PATCH 104/182] Qt: revert paintEvent changes, only keep one for ShaderParamsDialog --- ui/drivers/qt/shaderparamsdialog.cpp | 26 +++++----- ui/drivers/qt/shaderparamsdialog.h | 1 - ui/drivers/qt/ui_qt_window.cpp | 78 ---------------------------- ui/drivers/qt/viewoptionsdialog.cpp | 13 ----- ui/drivers/qt/viewoptionsdialog.h | 2 - ui/drivers/ui_qt.h | 10 ---- 6 files changed, 13 insertions(+), 117 deletions(-) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index bfbf9bf532..1891efccfa 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -91,6 +91,19 @@ void ShaderParamsDialog::closeEvent(QCloseEvent *event) emit closed(); } +void ShaderParamsDialog::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QDialog::paintEvent(event); +} + QString ShaderParamsDialog::getFilterLabel(unsigned filter) { QString filterString; @@ -1153,16 +1166,3 @@ void ShaderParamsDialog::onShaderParamDoubleSpinBoxValueChanged(double value) } } } - -void ShaderParamsDialog::paintEvent(QPaintEvent *event) -{ - QStyleOption o; - QPainter p; - o.initFrom(this); - p.begin(this); - style()->drawPrimitive( - QStyle::PE_Widget, &o, &p, this); - p.end(); - - QDialog::paintEvent(event); -} diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h index 73c6f82423..9e74d20c20 100644 --- a/ui/drivers/qt/shaderparamsdialog.h +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -5,7 +5,6 @@ class QCloseEvent; class QResizeEvent; -class QPaintEvent; class QVBoxLayout; class QFormLayout; class QLayout; diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 7d980f7093..9e64b80a69 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -191,19 +191,6 @@ void TreeView::selectionChanged(const QItemSelection &selected, const QItemSelec emit itemsSelected(list); } -void TreeView::paintEvent(QPaintEvent *event) -{ - QStyleOption o; - QPainter p; - o.initFrom(this); - p.begin(this); - style()->drawPrimitive( - QStyle::PE_Widget, &o, &p, this); - p.end(); - - QTreeView::paintEvent(event); -} - TableWidget::TableWidget(QWidget *parent) : QTableWidget(parent) { @@ -225,38 +212,12 @@ void TableWidget::keyPressEvent(QKeyEvent *event) QTableWidget::keyPressEvent(event); } -void TableWidget::paintEvent(QPaintEvent *event) -{ - QStyleOption o; - QPainter p; - o.initFrom(this); - p.begin(this); - style()->drawPrimitive( - QStyle::PE_Widget, &o, &p, this); - p.end(); - - QTableWidget::paintEvent(event); -} - CoreInfoLabel::CoreInfoLabel(QString text, QWidget *parent) : QLabel(text, parent) { setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); } -void CoreInfoLabel::paintEvent(QPaintEvent *event) -{ - QStyleOption o; - QPainter p; - o.initFrom(this); - p.begin(this); - style()->drawPrimitive( - QStyle::PE_Widget, &o, &p, this); - p.end(); - - QLabel::paintEvent(event); -} - CoreInfoWidget::CoreInfoWidget(CoreInfoLabel *label, QWidget *parent) : QWidget(parent) ,m_label(label) @@ -277,19 +238,6 @@ void CoreInfoWidget::resizeEvent(QResizeEvent *event) m_scrollArea->resize(event->size()); } -void CoreInfoWidget::paintEvent(QPaintEvent *event) -{ - QStyleOption o; - QPainter p; - o.initFrom(this); - p.begin(this); - style()->drawPrimitive( - QStyle::PE_Widget, &o, &p, this); - p.end(); - - QWidget::paintEvent(event); -} - LogTextEdit::LogTextEdit(QWidget *parent) : QPlainTextEdit(parent) { @@ -305,19 +253,6 @@ void LogTextEdit::appendMessage(const QString& text) verticalScrollBar()->setValue(verticalScrollBar()->maximum()); } -void LogTextEdit::paintEvent(QPaintEvent *event) -{ - QStyleOption o; - QPainter p; - o.initFrom(this); - p.begin(this); - style()->drawPrimitive( - QStyle::PE_Widget, &o, &p, this); - p.end(); - - QPlainTextEdit::paintEvent(event); -} - MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) ,m_loadCoreWindow(new LoadCoreWindow(this)) @@ -3012,19 +2947,6 @@ void MainWindow::onShowInfoMessage(QString msg) showMessageBox(msg, MainWindow::MSGBOX_TYPE_INFO, Qt::ApplicationModal, false); } -void MainWindow::paintEvent(QPaintEvent *event) -{ - QStyleOption o; - QPainter p; - o.initFrom(this); - p.begin(this); - style()->drawPrimitive( - QStyle::PE_Widget, &o, &p, this); - p.end(); - - QMainWindow::paintEvent(event); -} - static void* ui_window_qt_init(void) { ui_window.qtWindow = new MainWindow(); diff --git a/ui/drivers/qt/viewoptionsdialog.cpp b/ui/drivers/qt/viewoptionsdialog.cpp index fc265b6af0..a293b01a00 100644 --- a/ui/drivers/qt/viewoptionsdialog.cpp +++ b/ui/drivers/qt/viewoptionsdialog.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include "viewoptionsdialog.h" #include "../ui_qt.h" @@ -217,15 +216,3 @@ void ViewOptionsDialog::hideDialog() reject(); } -void ViewOptionsDialog::paintEvent(QPaintEvent *event) -{ - QStyleOption o; - QPainter p; - o.initFrom(this); - p.begin(this); - style()->drawPrimitive( - QStyle::PE_Widget, &o, &p, this); - p.end(); - - QDialog::paintEvent(event); -} diff --git a/ui/drivers/qt/viewoptionsdialog.h b/ui/drivers/qt/viewoptionsdialog.h index 1ceb70f313..7b5c7c71fe 100644 --- a/ui/drivers/qt/viewoptionsdialog.h +++ b/ui/drivers/qt/viewoptionsdialog.h @@ -44,8 +44,6 @@ private: QCheckBox *m_suggestLoadedCoreFirstCheckBox; QSpinBox *m_allPlaylistsListMaxCountSpinBox; QSpinBox *m_allPlaylistsGridMaxCountSpinBox; -protected: - void paintEvent(QPaintEvent *event); }; #endif diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index c04ae44173..0b8debb3b9 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -153,8 +153,6 @@ signals: protected slots: void columnCountChanged(int oldCount, int newCount); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); -protected: - void paintEvent(QPaintEvent *event); }; class TableWidget : public QTableWidget @@ -167,8 +165,6 @@ signals: void deletePressed(); protected: void keyPressEvent(QKeyEvent *event); -protected: - void paintEvent(QPaintEvent *event); }; class AppHandler : public QObject @@ -190,8 +186,6 @@ class CoreInfoLabel : public QLabel Q_OBJECT public: CoreInfoLabel(QString text = QString(), QWidget *parent = 0); -protected: - void paintEvent(QPaintEvent *event); }; class CoreInfoWidget : public QWidget @@ -202,7 +196,6 @@ public: QSize sizeHint() const; protected: void resizeEvent(QResizeEvent *event); - void paintEvent(QPaintEvent *event); private: CoreInfoLabel *m_label; QScrollArea *m_scrollArea; @@ -215,8 +208,6 @@ public: LogTextEdit(QWidget *parent = 0); public slots: void appendMessage(const QString& text); -protected: - void paintEvent(QPaintEvent *event); }; class MainWindow : public QMainWindow @@ -459,7 +450,6 @@ private: protected: void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *event); - void paintEvent(QPaintEvent *event); }; Q_DECLARE_METATYPE(ThumbnailWidget) From 7568d350865b0744f85bad8890ce364fcfdbddd3 Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Mon, 20 Aug 2018 08:30:54 -0500 Subject: [PATCH 105/182] discord: replace forward slashes with underscores --- discord/discord.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/discord/discord.c b/discord/discord.c index 25e6375f47..1baff336ac 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -116,7 +116,9 @@ void discord_update(enum discord_presence presence) if (core_info) { const char *core_name = core_info->core_name ? core_info->core_name : "core"; - const char *system_name = string_replace_substring(string_to_lower((char *)core_name), " ", "_"); + + const char *system_name = string_replace_substring( + string_replace_substring(string_to_lower((char *)core_name), " ", "_"), "/", "_"); char *label = NULL; playlist_t *current_playlist = playlist_get_cached(); From 0ed43eb908597c6f88715c5afe751e38be7c41be Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 20 Aug 2018 12:57:05 -0400 Subject: [PATCH 106/182] Qt: fix tool button handling on shader window --- ui/drivers/qt/shaderparamsdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 1891efccfa..2d17741753 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -314,7 +314,7 @@ void ShaderParamsDialog::onScaleComboBoxIndexChanged(int) void ShaderParamsDialog::onShaderPassMoveDownClicked() { - QPushButton *button = qobject_cast(sender()); + QToolButton *button = qobject_cast(sender()); QVariant passVariant; struct video_shader *menu_shader = NULL; struct video_shader *video_shader = NULL; @@ -360,7 +360,7 @@ void ShaderParamsDialog::onShaderPassMoveDownClicked() void ShaderParamsDialog::onShaderPassMoveUpClicked() { - QPushButton *button = qobject_cast(sender()); + QToolButton *button = qobject_cast(sender()); QVariant passVariant; struct video_shader *menu_shader = NULL; struct video_shader *video_shader = NULL; From bb451d59e80933fc9023a8f73e42a75b9ca1f020 Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Mon, 20 Aug 2018 14:03:06 -0500 Subject: [PATCH 107/182] discord: hardcoded non-essential cores into discord.c --- discord/discord.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/discord/discord.c b/discord/discord.c index 1baff336ac..211eb0981c 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -35,6 +35,27 @@ static bool discord_ready = false; static bool in_menu = false; static unsigned discord_status = 0; +// If you are to add to this list, please use the `corename` attribute +// from the core's respective info file. Case sensitivity does not matter. +char missing_core_icons[][16] = { + "3D Engine", + "Cannonball", + "Daphne", + "FFmpeg", + "Game Music Emu", + "Imageviewer", + "Lutro", + "MESS 2014 (Git)", + "PocketCDG", + "REminiscence", + "RemoteJoy", + "Rustation", + "Theodore", + "ThePowderToy", + "UME 2014 (Git)", + "VeMUlator" +}; + DiscordRichPresence discord_presence; static void handle_discord_ready(const DiscordUser* connectedUser) @@ -135,6 +156,18 @@ void discord_update(enum discord_presence presence) #endif discord_presence.largeImageKey = system_name; + for (int i = 0; i < sizeof(missing_core_icons) / sizeof(missing_core_icons[0]); i++) + { + const char *item = string_replace_substring( + string_replace_substring(string_to_lower(missing_core_icons[i]), " ", "_"), "/", "_"); + + if (strcmp(item, core_name)) + { + discord_presence.largeImageKey = "core"; + break; + } + } + if (core_info->display_name) discord_presence.largeImageText = core_info->display_name; @@ -143,8 +176,6 @@ void discord_update(enum discord_presence presence) else start_time = start_time + difftime(time(0), pause_time); - RARCH_LOG("%d\n", start_time); - if (!skip) { discord_presence.smallImageKey = "playing"; From f507905345bf52cb021e989fb108ea86799c63d7 Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Mon, 20 Aug 2018 14:14:35 -0500 Subject: [PATCH 108/182] discord: fixed the corename comparison statement --- discord/discord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/discord.c b/discord/discord.c index 211eb0981c..e8ea32626b 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -161,7 +161,7 @@ void discord_update(enum discord_presence presence) const char *item = string_replace_substring( string_replace_substring(string_to_lower(missing_core_icons[i]), " ", "_"), "/", "_"); - if (strcmp(item, core_name)) + if (strcmp(item, core_name) == 0) { discord_presence.largeImageKey = "core"; break; From ea561c8dfebf39f2290e8b16562983721d2d3fc6 Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Mon, 20 Aug 2018 14:16:52 -0500 Subject: [PATCH 109/182] discord: see the previous commit message --- discord/discord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/discord.c b/discord/discord.c index e8ea32626b..fc34a2e79d 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -161,7 +161,7 @@ void discord_update(enum discord_presence presence) const char *item = string_replace_substring( string_replace_substring(string_to_lower(missing_core_icons[i]), " ", "_"), "/", "_"); - if (strcmp(item, core_name) == 0) + if (strcmp(item, system_name) == 0) { discord_presence.largeImageKey = "core"; break; From e9c68597ff408fd253cc6d9db9ded1742da0f563 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 20 Aug 2018 18:47:18 -0400 Subject: [PATCH 110/182] Qt: try to work around layout crashing issues on Windows --- ui/drivers/qt/shaderparamsdialog.cpp | 91 +++++++++++----------------- ui/drivers/qt/shaderparamsdialog.h | 8 ++- 2 files changed, 43 insertions(+), 56 deletions(-) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 2d17741753..c6347dde80 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "shaderparamsdialog.h" #include "../ui_qt.h" @@ -41,25 +42,13 @@ enum ShaderParamsDialog::ShaderParamsDialog(QWidget *parent) : QDialog(parent) - ,m_layout(NULL) + ,m_layout() + ,m_scrollArea() { - QScrollArea *scrollArea = NULL; - QWidget *widget = NULL; - setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); setObjectName("shaderParamsDialog"); - m_layout = new QVBoxLayout(); - - widget = new QWidget(); - widget->setLayout(m_layout); - widget->setObjectName("shaderParamsWidget"); - scrollArea = new QScrollArea(this); - scrollArea->setWidgetResizable(true); - scrollArea->setWidget(widget); - scrollArea->setObjectName("shaderParamsScrollArea"); - - setProperty("scrollArea", QVariant::fromValue(scrollArea)); + QTimer::singleShot(0, this, SLOT(clearLayout())); } ShaderParamsDialog::~ShaderParamsDialog() @@ -68,20 +57,12 @@ ShaderParamsDialog::~ShaderParamsDialog() void ShaderParamsDialog::resizeEvent(QResizeEvent *event) { - QVariant scrollAreaVariant = property("scrollArea"); - QScrollArea *scrollArea = NULL; - QDialog::resizeEvent(event); - if (!scrollAreaVariant.isValid()) + if (!m_scrollArea) return; - scrollArea = scrollAreaVariant.value(); - - if (!scrollArea) - return; - - scrollArea->resize(event->size()); + m_scrollArea->resize(event->size()); } void ShaderParamsDialog::closeEvent(QCloseEvent *event) @@ -126,35 +107,30 @@ QString ShaderParamsDialog::getFilterLabel(unsigned filter) return filterString; } -void ShaderParamsDialog::clearLayout(QLayout *layout) +void ShaderParamsDialog::clearLayout() { - QLayoutItem *child = NULL; + QWidget *widget = NULL; - while (layout->count() && ((child = layout->takeAt(0)) != 0)) + if (m_scrollArea) { - QWidget *widget = child->widget(); - QLayout *childLayout = child->layout(); - - if (widget) - { - QLayout *widgetLayout = widget->layout(); - - if (widgetLayout) - clearLayout(widgetLayout); - - /* deleteLater() doesn't work right for some reason here, - * so just disconnect any signals in case there are pending events, - * and delete the widget immediately. - */ - widget->disconnect(); - delete widget; - } - - if (childLayout) - clearLayout(childLayout); - - delete child; + //qDeleteAll(children()); + foreach (QObject *obj, children()) + obj->deleteLater(); } + + m_layout = new QVBoxLayout(); + + widget = new QWidget(); + widget->setLayout(m_layout); + widget->setObjectName("shaderParamsWidget"); + + m_scrollArea = new QScrollArea(); + + m_scrollArea->setParent(this); + m_scrollArea->setWidgetResizable(true); + m_scrollArea->setWidget(widget); + m_scrollArea->setObjectName("shaderParamsScrollArea"); + m_scrollArea->show(); } void ShaderParamsDialog::getShaders(struct video_shader **menu_shader, struct video_shader **video_shader) @@ -597,7 +573,7 @@ void ShaderParamsDialog::onShaderClearAllPassesClicked() while (menu_shader->passes > 0) menu_shader_manager_decrement_amount_passes(); - onShaderApplyClicked(); + emit onShaderApplyClicked(); #endif } @@ -638,7 +614,7 @@ void ShaderParamsDialog::onShaderRemovePassClicked() menu_shader_manager_decrement_amount_passes(); - onShaderApplyClicked(); + emit onShaderApplyClicked(); #endif } @@ -648,6 +624,11 @@ void ShaderParamsDialog::onShaderApplyClicked() } void ShaderParamsDialog::reload() +{ + buildLayout(); +} + +void ShaderParamsDialog::buildLayout() { QPushButton *loadButton = NULL; QPushButton *saveButton = NULL; @@ -677,7 +658,7 @@ void ShaderParamsDialog::reload() goto end; } - clearLayout(m_layout); + clearLayout(); /* Only check video_shader for the path, menu_shader seems stale... e.g. if you remove all the shader passes, * it still has the old path in it, but video_shader does not @@ -861,8 +842,10 @@ void ShaderParamsDialog::reload() m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); end: - resize(720, 480); + /* Why is this required?? The layout is corrupt without both resizes. */ + resize(720 + 1, 480); show(); + resize(720, 480); } void ShaderParamsDialog::addShaderParam(struct video_shader_parameter *param, int parameter, QFormLayout *form) diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h index 9e74d20c20..398ff283b1 100644 --- a/ui/drivers/qt/shaderparamsdialog.h +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -2,12 +2,14 @@ #define SHADERPARAMSDIALOG_H #include +#include class QCloseEvent; class QResizeEvent; class QVBoxLayout; class QFormLayout; class QLayout; +class QScrollArea; class ShaderParamsDialog : public QDialog { @@ -38,14 +40,16 @@ private slots: void onShaderClearAllPassesClicked(); void onShaderRemovePassClicked(); void onShaderApplyClicked(); + void clearLayout(); + void buildLayout(); private: QString getFilterLabel(unsigned filter); void addShaderParam(struct video_shader_parameter *param, int parameter, QFormLayout *form); - void clearLayout(QLayout *layout); void getShaders(struct video_shader **menu_shader, struct video_shader **video_shader); void saveShaderPreset(const char *path, unsigned action_type); - QVBoxLayout *m_layout; + QPointer m_layout; + QPointer m_scrollArea; protected: void closeEvent(QCloseEvent *event); void resizeEvent(QResizeEvent *event); From 4d09ddde1cb266de78719096cb466062e65b3165 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 20 Aug 2018 20:26:50 -0400 Subject: [PATCH 111/182] Qt: limit shader preset/pass selection to the appropriate extensions --- gfx/video_shader_parse.c | 9 +++-- ui/drivers/qt/shaderparamsdialog.cpp | 49 ++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index 33e0c1674c..6151618f15 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -1136,11 +1136,16 @@ enum rarch_shader_type video_shader_get_type_from_ext( { enum gfx_ctx_api api = video_context_driver_get_api(); + if (string_is_empty(ext)) + return RARCH_SHADER_NONE; + + if (strlen(ext) > 1 && ext[0] == '.') + ext++; + *is_preset = false; if ( - string_is_equal(ext, "cg") || - string_is_equal(ext, "CG") + string_is_equal_case_insensitive(ext, "cg") ) { switch (api) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index c6347dde80..960aba8ec6 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -27,6 +27,7 @@ extern "C" { #include "../../../configuration.h" #include "../../../retroarch.h" #include "../../../paths.h" +#include "../../../file_path_special.h" #ifdef HAVE_MENU #include "../../../menu/menu_shader.h" #endif @@ -384,12 +385,14 @@ void ShaderParamsDialog::onShaderLoadPresetClicked() { #ifdef HAVE_MENU QString path; + QString filter; QByteArray pathArray; struct video_shader *menu_shader = NULL; struct video_shader *video_shader = NULL; const char *pathData = NULL; settings_t *settings = config_get_ptr(); enum rarch_shader_type type = RARCH_SHADER_NONE; + bool is_preset = false; if (!settings) return; @@ -399,7 +402,27 @@ void ShaderParamsDialog::onShaderLoadPresetClicked() if (!menu_shader) return; - path = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), settings->paths.directory_video_shader); + filter = "Shader Preset ("; + + /* NOTE: Maybe we should have a way to get a list of all shader types instead of hard-coding this? */ + if (video_shader_is_supported(RARCH_SHADER_CG) && + video_shader_get_type_from_ext(file_path_str(FILE_PATH_CGP_EXTENSION), &is_preset) + != RARCH_SHADER_NONE) + filter += QLatin1Literal("*") + file_path_str(FILE_PATH_CGP_EXTENSION); + + if (video_shader_is_supported(RARCH_SHADER_GLSL) && + video_shader_get_type_from_ext(file_path_str(FILE_PATH_GLSLP_EXTENSION), &is_preset) + != RARCH_SHADER_NONE) + filter += QLatin1Literal(" *") + file_path_str(FILE_PATH_GLSLP_EXTENSION); + + if (video_shader_is_supported(RARCH_SHADER_SLANG) && + video_shader_get_type_from_ext(file_path_str(FILE_PATH_SLANGP_EXTENSION), &is_preset) + != RARCH_SHADER_NONE) + filter += QLatin1Literal(" *") + file_path_str(FILE_PATH_SLANGP_EXTENSION); + + filter += ")"; + + path = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), settings->paths.directory_video_shader, filter); if (path.isEmpty()) return; @@ -417,12 +440,14 @@ void ShaderParamsDialog::onShaderAddPassClicked() { #ifdef HAVE_MENU QString path; + QString filter; QByteArray pathArray; struct video_shader *menu_shader = NULL; struct video_shader *video_shader = NULL; struct video_shader_pass *shader_pass = NULL; const char *pathData = NULL; settings_t *settings = config_get_ptr(); + bool is_preset = false; if (!settings) return; @@ -432,7 +457,27 @@ void ShaderParamsDialog::onShaderAddPassClicked() if (!menu_shader) return; - path = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), settings->paths.directory_video_shader); + filter = "Shader ("; + + /* NOTE: Maybe we should have a way to get a list of all shader types instead of hard-coding this? */ + if (video_shader_is_supported(RARCH_SHADER_CG) && + video_shader_get_type_from_ext(".cg", &is_preset) + != RARCH_SHADER_NONE) + filter += QLatin1Literal("*.cg"); + + if (video_shader_is_supported(RARCH_SHADER_GLSL) && + video_shader_get_type_from_ext(".glsl", &is_preset) + != RARCH_SHADER_NONE) + filter += QLatin1Literal(" *.glsl"); + + if (video_shader_is_supported(RARCH_SHADER_SLANG) && + video_shader_get_type_from_ext(".slang", &is_preset) + != RARCH_SHADER_NONE) + filter += QLatin1Literal(" *.slang"); + + filter += ")"; + + path = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), settings->paths.directory_video_shader, filter); if (path.isEmpty()) return; From ff09503ac10247caec91f0f6e5745f1f240059db Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 20 Aug 2018 21:48:59 -0400 Subject: [PATCH 112/182] Qt: add right-click options to reset shader parameters back to defaults --- intl/msg_hash_ja.h | 6 + intl/msg_hash_us.h | 6 + msg_hash.h | 3 + ui/drivers/qt/shaderparamsdialog.cpp | 187 ++++++++++++++++++++++++++- ui/drivers/qt/shaderparamsdialog.h | 5 + 5 files changed, 202 insertions(+), 5 deletions(-) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 88adc933c0..e13ceb1c71 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3774,3 +3774,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, "すべてのパスを取り除く") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, "シェーダーパスはありません。") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_PASS, + "このパスをリセット") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, + "すべてのパスをリセット") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, + "パラメータをリセット") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 8bb57653c9..6fa7aca4cf 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -4284,3 +4284,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, "Clear All Passes") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, "No shader passes.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_PASS, + "Reset Pass") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, + "Reset All Passes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, + "Reset Parameter") diff --git a/msg_hash.h b/msg_hash.h index 5ea9620d1c..483178f62c 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1992,6 +1992,9 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, + MENU_ENUM_LABEL_VALUE_QT_RESET_PASS, + MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, + MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 960aba8ec6..5ce8a387be 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -114,9 +114,10 @@ void ShaderParamsDialog::clearLayout() if (m_scrollArea) { - //qDeleteAll(children()); foreach (QObject *obj, children()) + { obj->deleteLater(); + } } m_layout = new QVBoxLayout(); @@ -436,6 +437,85 @@ void ShaderParamsDialog::onShaderLoadPresetClicked() #endif } +void ShaderParamsDialog::onShaderResetPass(int pass) +{ + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + unsigned i; + + getShaders(&menu_shader, &video_shader); + + if (menu_shader) + { + for (i = 0; i < menu_shader->num_parameters; i++) + { + struct video_shader_parameter *param = &menu_shader->parameters[i]; + + /* if pass < 0, reset all params, otherwise only reset the selected pass */ + if (pass >= 0 && param->pass != pass) + continue; + + param->current = param->initial; + } + } + + if (video_shader) + { + for (i = 0; i < video_shader->num_parameters; i++) + { + struct video_shader_parameter *param = &video_shader->parameters[i]; + + /* if pass < 0, reset all params, otherwise only reset the selected pass */ + if (pass >= 0 && param->pass != pass) + continue; + + param->current = param->initial; + } + } + + emit reload(); +} + +void ShaderParamsDialog::onShaderResetParameter(int parameter) +{ + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + unsigned i; + + getShaders(&menu_shader, &video_shader); + + if (menu_shader) + { + struct video_shader_parameter *param = NULL; + + if (parameter < 0 || parameter >= static_cast(menu_shader->num_parameters)) + return; + + param = &menu_shader->parameters[parameter]; + + param->current = param->initial; + } + + if (video_shader) + { + struct video_shader_parameter *param = NULL; + + if (parameter < 0 || parameter >= static_cast(video_shader->num_parameters)) + return; + + param = &video_shader->parameters[parameter]; + + param->current = param->initial; + } + + emit reload(); +} + +void ShaderParamsDialog::onShaderResetAllPasses() +{ + emit onShaderResetPass(-1); +} + void ShaderParamsDialog::onShaderAddPassClicked() { #ifdef HAVE_MENU @@ -670,7 +750,7 @@ void ShaderParamsDialog::onShaderApplyClicked() void ShaderParamsDialog::reload() { - buildLayout(); + emit buildLayout(); } void ShaderParamsDialog::buildLayout() @@ -703,7 +783,7 @@ void ShaderParamsDialog::buildLayout() goto end; } - clearLayout(); + emit clearLayout(); /* Only check video_shader for the path, menu_shader seems stale... e.g. if you remove all the shader passes, * it still has the old path in it, but video_shader does not @@ -846,6 +926,10 @@ void ShaderParamsDialog::buildLayout() form = new QFormLayout(); groupBox = new QGroupBox(shaderBasename); groupBox->setLayout(form); + groupBox->setProperty("pass", i); + groupBox->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(groupBox, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onGroupBoxContextMenuRequested(const QPoint&))); m_layout->addWidget(groupBox); @@ -893,9 +977,102 @@ end: resize(720, 480); } +void ShaderParamsDialog::onParameterLabelContextMenuRequested(const QPoint&) +{ + QLabel *label = NULL; + QPointer action; + QList actions; + QScopedPointer resetParamAction; + QVariant paramVariant; + int parameter = 0; + bool ok = false; + + label = qobject_cast(sender()); + + if (!label) + return; + + paramVariant = label->property("parameter"); + + if (!paramVariant.isValid()) + return; + + parameter = paramVariant.toInt(&ok); + + if (!ok) + return; + + resetParamAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER), 0)); + + actions.append(resetParamAction.data()); + + action = QMenu::exec(actions, QCursor::pos(), NULL, label); + + if (!action) + return; + + if (action == resetParamAction.data()) + { + emit onShaderResetParameter(parameter); + } +} + +void ShaderParamsDialog::onGroupBoxContextMenuRequested(const QPoint&) +{ + QGroupBox *groupBox = NULL; + QPointer action; + QList actions; + QScopedPointer resetPassAction; + QScopedPointer resetAllPassesAction; + QVariant passVariant; + int pass = 0; + bool ok = false; + + groupBox = qobject_cast(sender()); + + if (!groupBox) + return; + + passVariant = groupBox->property("pass"); + + if (!passVariant.isValid()) + return; + + pass = passVariant.toInt(&ok); + + if (!ok) + return; + + resetPassAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_RESET_PASS), 0)); + resetAllPassesAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES), 0)); + + actions.append(resetPassAction.data()); + actions.append(resetAllPassesAction.data()); + + action = QMenu::exec(actions, QCursor::pos(), NULL, groupBox); + + if (!action) + return; + + if (action == resetPassAction.data()) + { + emit onShaderResetPass(pass); + } + else if (action == resetAllPassesAction.data()) + { + emit onShaderResetAllPasses(); + } +} + void ShaderParamsDialog::addShaderParam(struct video_shader_parameter *param, int parameter, QFormLayout *form) { QString desc = param->desc; + QLabel *label = new QLabel(desc); + + label->setProperty("parameter", parameter); + label->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(label, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onParameterLabelContextMenuRequested(const QPoint&))); if ((param->minimum == 0.0) && (param->maximum @@ -909,7 +1086,7 @@ void ShaderParamsDialog::addShaderParam(struct video_shader_parameter *param, in connect(checkBox, SIGNAL(clicked()), this, SLOT(onShaderParamCheckBoxClicked())); - form->addRow(desc, checkBox); + form->addRow(label, checkBox); } else { @@ -957,7 +1134,7 @@ void ShaderParamsDialog::addShaderParam(struct video_shader_parameter *param, in box->addWidget(spinBox); } - form->addRow(desc, box); + form->addRow(label, box); } } diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h index 398ff283b1..309e785234 100644 --- a/ui/drivers/qt/shaderparamsdialog.h +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -28,9 +28,14 @@ private slots: void onShaderParamSpinBoxValueChanged(int value); void onShaderParamDoubleSpinBoxValueChanged(double value); void onFilterComboBoxIndexChanged(int index); + void onGroupBoxContextMenuRequested(const QPoint &pos); + void onParameterLabelContextMenuRequested(const QPoint &pos); void onScaleComboBoxIndexChanged(int index); void onShaderPassMoveDownClicked(); void onShaderPassMoveUpClicked(); + void onShaderResetPass(int pass); + void onShaderResetAllPasses(); + void onShaderResetParameter(int parameter); void onShaderLoadPresetClicked(); void onShaderAddPassClicked(); void onShaderSavePresetAsClicked(); From 6a4584e3014a0d75caa10bc8d21d3f041d4c722d Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 20 Aug 2018 21:49:50 -0400 Subject: [PATCH 113/182] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 4adbdf50d1..cdb99fd1c5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -21,6 +21,7 @@ - MENU/QT/WIMP: Initial grid view. - MENU/QT/WIMP: Drag&drop to add new playlist items, add option to add/edit/delete playlists. - MENU/QT/WIMP: Add menu option to update RetroArch (Windows only for now). +- MENU/QT/WIMP: Add menu option to manage shaders. - MENU/XMB: Add new icons for the settings - MENU/XMB: Add an option to show the desktop ui - METAL: Initial work-in-progress video driver for Metal. macOS-only right now, and currently requires macOS 10.13. From c276f9349aaf71213beea6c12d1f7fcd867a959e Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Mon, 20 Aug 2018 20:55:44 -0500 Subject: [PATCH 114/182] discord: remove hardcoded values and use new attribute --- core_info.c | 9 +++++++++ core_info.h | 1 + discord/discord.c | 42 +++--------------------------------------- 3 files changed, 13 insertions(+), 39 deletions(-) diff --git a/core_info.c b/core_info.c index 15c5a0a32b..f31ad39295 100644 --- a/core_info.c +++ b/core_info.c @@ -149,6 +149,7 @@ static void core_info_list_free(core_info_list_t *core_info_list) free(info->path); free(info->core_name); free(info->systemname); + free(info->rpc_name); free(info->system_manufacturer); free(info->display_name); free(info->display_version); @@ -302,6 +303,14 @@ static core_info_list_t *core_info_list_new(const char *path, tmp = NULL; } + if (config_get_string(conf, "rpcname", &tmp) + && !string_is_empty(tmp)) + { + core_info[i].rpc_name = strdup(tmp); + free(tmp); + tmp = NULL; + } + if (config_get_string(conf, "manufacturer", &tmp) && !string_is_empty(tmp)) { diff --git a/core_info.h b/core_info.h index f87805e605..d6c9546283 100644 --- a/core_info.h +++ b/core_info.h @@ -47,6 +47,7 @@ typedef struct char *core_name; char *system_manufacturer; char *systemname; + char *rpc_name; char *supported_extensions; char *authors; char *permissions; diff --git a/discord/discord.c b/discord/discord.c index fc34a2e79d..d93afeea76 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -35,27 +35,6 @@ static bool discord_ready = false; static bool in_menu = false; static unsigned discord_status = 0; -// If you are to add to this list, please use the `corename` attribute -// from the core's respective info file. Case sensitivity does not matter. -char missing_core_icons[][16] = { - "3D Engine", - "Cannonball", - "Daphne", - "FFmpeg", - "Game Music Emu", - "Imageviewer", - "Lutro", - "MESS 2014 (Git)", - "PocketCDG", - "REminiscence", - "RemoteJoy", - "Rustation", - "Theodore", - "ThePowderToy", - "UME 2014 (Git)", - "VeMUlator" -}; - DiscordRichPresence discord_presence; static void handle_discord_ready(const DiscordUser* connectedUser) @@ -136,10 +115,7 @@ void discord_update(enum discord_presence presence) case DISCORD_PRESENCE_GAME: if (core_info) { - const char *core_name = core_info->core_name ? core_info->core_name : "core"; - - const char *system_name = string_replace_substring( - string_replace_substring(string_to_lower((char *)core_name), " ", "_"), "/", "_"); + const char *rpc_name = core_info->rpc_name ? core_info->rpc_name : "core"; char *label = NULL; playlist_t *current_playlist = playlist_get_cached(); @@ -151,22 +127,10 @@ void discord_update(enum discord_presence presence) if (!label) label = (char *)path_basename(path_get(RARCH_PATH_BASENAME)); #if 1 - RARCH_LOG("[Discord] current core: %s\n", system_name); + RARCH_LOG("[Discord] current core: %s\n", rpc_name); RARCH_LOG("[Discord] current content: %s\n", label); #endif - discord_presence.largeImageKey = system_name; - - for (int i = 0; i < sizeof(missing_core_icons) / sizeof(missing_core_icons[0]); i++) - { - const char *item = string_replace_substring( - string_replace_substring(string_to_lower(missing_core_icons[i]), " ", "_"), "/", "_"); - - if (strcmp(item, system_name) == 0) - { - discord_presence.largeImageKey = "core"; - break; - } - } + discord_presence.largeImageKey = rpc_name; if (core_info->display_name) discord_presence.largeImageText = core_info->display_name; From 281966a14c48130e3a8fc6145988cd8808bec010 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 21 Aug 2018 10:15:00 -0400 Subject: [PATCH 115/182] Qt: make sure video_shader exists --- ui/drivers/qt/shaderparamsdialog.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 5ce8a387be..3f75ce9940 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -778,17 +778,14 @@ void ShaderParamsDialog::buildLayout() */ if ((video_shader && video_shader->passes == 0) || !video_shader) - { setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); - goto end; - } emit clearLayout(); /* Only check video_shader for the path, menu_shader seems stale... e.g. if you remove all the shader passes, * it still has the old path in it, but video_shader does not */ - if (!string_is_empty(video_shader->path)) + if (video_shader && !string_is_empty(video_shader->path)) { shader_path = video_shader->path; setWindowTitle(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER)) + ": " + QFileInfo(shader_path).fileName()); @@ -847,7 +844,7 @@ void ShaderParamsDialog::buildLayout() m_layout->addLayout(topButtonLayout); /* NOTE: We assume that parameters are always grouped in order by the pass number, e.g., all parameters for pass 0 come first, then params for pass 1, etc. */ - for (i = 0; i < static_cast(video_shader->passes); i++) + for (i = 0; video_shader && i < static_cast(video_shader->passes); i++) { QFormLayout *form = NULL; QGroupBox *groupBox = NULL; @@ -970,7 +967,6 @@ void ShaderParamsDialog::buildLayout() m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); -end: /* Why is this required?? The layout is corrupt without both resizes. */ resize(720 + 1, 480); show(); From f6a0b09e7dc60856c8d05cc741db1d799a2cbeac Mon Sep 17 00:00:00 2001 From: Jesse Bryan Date: Tue, 21 Aug 2018 09:41:16 -0500 Subject: [PATCH 116/182] general: renamed rpcname to systemid --- core_info.c | 6 +++--- core_info.h | 2 +- discord/discord.c | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core_info.c b/core_info.c index f31ad39295..18c8caf448 100644 --- a/core_info.c +++ b/core_info.c @@ -149,7 +149,7 @@ static void core_info_list_free(core_info_list_t *core_info_list) free(info->path); free(info->core_name); free(info->systemname); - free(info->rpc_name); + free(info->system_id); free(info->system_manufacturer); free(info->display_name); free(info->display_version); @@ -303,10 +303,10 @@ static core_info_list_t *core_info_list_new(const char *path, tmp = NULL; } - if (config_get_string(conf, "rpcname", &tmp) + if (config_get_string(conf, "systemid", &tmp) && !string_is_empty(tmp)) { - core_info[i].rpc_name = strdup(tmp); + core_info[i].system_id = strdup(tmp); free(tmp); tmp = NULL; } diff --git a/core_info.h b/core_info.h index d6c9546283..1390dac56d 100644 --- a/core_info.h +++ b/core_info.h @@ -47,7 +47,7 @@ typedef struct char *core_name; char *system_manufacturer; char *systemname; - char *rpc_name; + char *system_id; char *supported_extensions; char *authors; char *permissions; diff --git a/discord/discord.c b/discord/discord.c index d93afeea76..8e1ba00e70 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -115,7 +115,7 @@ void discord_update(enum discord_presence presence) case DISCORD_PRESENCE_GAME: if (core_info) { - const char *rpc_name = core_info->rpc_name ? core_info->rpc_name : "core"; + const char *system_id = core_info->system_id ? core_info->system_id : "core"; char *label = NULL; playlist_t *current_playlist = playlist_get_cached(); @@ -127,10 +127,10 @@ void discord_update(enum discord_presence presence) if (!label) label = (char *)path_basename(path_get(RARCH_PATH_BASENAME)); #if 1 - RARCH_LOG("[Discord] current core: %s\n", rpc_name); + RARCH_LOG("[Discord] current core: %s\n", system_id); RARCH_LOG("[Discord] current content: %s\n", label); #endif - discord_presence.largeImageKey = rpc_name; + discord_presence.largeImageKey = system_id; if (core_info->display_name) discord_presence.largeImageText = core_info->display_name; From cc16c45069cb2181597c2d4f0e4161c51b3388d0 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 21 Aug 2018 11:14:42 -0400 Subject: [PATCH 117/182] Qt: keep size of shader window when reloading if user has changed it --- ui/drivers/qt/shaderparamsdialog.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 3f75ce9940..b7ed0a2cd0 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -49,6 +49,8 @@ ShaderParamsDialog::ShaderParamsDialog(QWidget *parent) : setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); setObjectName("shaderParamsDialog"); + resize(720, 480); + QTimer::singleShot(0, this, SLOT(clearLayout())); } @@ -968,9 +970,9 @@ void ShaderParamsDialog::buildLayout() m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); /* Why is this required?? The layout is corrupt without both resizes. */ - resize(720 + 1, 480); + resize(width() + 1, height()); show(); - resize(720, 480); + resize(width() - 1, height()); } void ShaderParamsDialog::onParameterLabelContextMenuRequested(const QPoint&) From 45bcd62f348585abcf3d06987fabe10834f5c5fe Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Tue, 21 Aug 2018 18:45:22 +0200 Subject: [PATCH 118/182] rename vrr runloop option --- intl/msg_hash_us.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 6fa7aca4cf..82a406bc13 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -690,7 +690,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_FPS_SHOW, MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, "Limit Maximum Run Speed") MSG_HASH(MENU_ENUM_LABEL_VALUE_VRR_RUNLOOP_ENABLE, - "VRR Runloop (G-Sync, FreeSync Mode)") + "Sync to Exact Content Framerate (G-Sync, FreeSync)") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, "Frame Throttle") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, @@ -3295,7 +3295,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_DISK_IMAGE_APPEND, MSG_HASH(MENU_ENUM_SUBLABEL_MENU_ENUM_THROTTLE_FRAMERATE, "Makes sure the framerate is capped while inside the menu.") MSG_HASH(MENU_ENUM_SUBLABEL_VRR_RUNLOOP_ENABLE, - "Force core requested timing for variable refresh rate screens.") + "No deviation from core requested timing. Use for Variable Refresh Rate screens, G-Sync, FreeSync.") MSG_HASH(MENU_ENUM_SUBLABEL_XMB_LAYOUT, "Select a different layout for the XMB interface.") MSG_HASH(MENU_ENUM_SUBLABEL_XMB_THEME, From 1c8f2beca3a4247def77af5a17db09b59b915b26 Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Tue, 21 Aug 2018 18:47:06 +0200 Subject: [PATCH 119/182] update vrr runloop help --- intl/msg_hash_us.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index 929df3049f..62651d118f 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -1256,10 +1256,12 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE: snprintf(s, len, - "VRR Runloop Mode.\n" + "Sync to Exact Content Framerate.\n" " \n" - "This option will force x1 speed \n" - "to ensure smooth scrolling."); + "This option is the equivalent of forcing x1 speed\n" + "while still allowing fast forward.\n" + "No deviation from the core requested refresh rate,\n" + "no sound Dynamic Rate Control)."); break; case MENU_ENUM_LABEL_VIDEO_MONITOR_INDEX: snprintf(s, len, From 8984162e0fc7c40b8f302eaf0ba753cb278c5e85 Mon Sep 17 00:00:00 2001 From: Alfrix Date: Tue, 21 Aug 2018 14:19:35 -0300 Subject: [PATCH 120/182] Change Reset core association icon to undo --- menu/drivers/xmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index ceccd0aa8e..9260bc1c56 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2223,7 +2223,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST: return xmb->textures.list[XMB_TEXTURE_ADD_FAVORITE]; case MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION: - return xmb->textures.list[XMB_TEXTURE_RENAME]; + return xmb->textures.list[XMB_TEXTURE_UNDO]; case MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS: return xmb->textures.list[XMB_TEXTURE_INPUT_REMAPPING_OPTIONS]; case MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS: From 06daa1f9ef0e3b3d039b80423f92afb1a4396a32 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 21 Aug 2018 13:39:16 -0400 Subject: [PATCH 121/182] Qt: start on history playlist by default, UI option to change it will come later --- ui/drivers/qt/playlist.cpp | 33 ++++++++++++++++++++++++-------- ui/drivers/qt/ui_qt_window.cpp | 11 +++++++++++ ui/drivers/ui_qt.cpp | 35 +++++++++++++++++++++++++++++++--- ui/drivers/ui_qt.h | 6 ++++++ 4 files changed, 74 insertions(+), 11 deletions(-) diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp index ef788d2c37..f2f1e4ef86 100644 --- a/ui/drivers/qt/playlist.cpp +++ b/ui/drivers/qt/playlist.cpp @@ -750,7 +750,10 @@ void MainWindow::reloadPlaylists() if (firstItem) { - bool found = false; + bool foundCurrent = false; + bool foundInitial = false; + QString initialPlaylist = m_settings->value("initial_playlist", m_historyPlaylistsItem->data(Qt::UserRole).toString()).toString(); + QListWidgetItem *initialItem = NULL; for (i = 0; i < m_listWidget->count(); i++) { @@ -761,21 +764,35 @@ void MainWindow::reloadPlaylists() { path = item->data(Qt::UserRole).toString(); - if (!currentPlaylistPath.isEmpty() && !path.isEmpty()) + if (!path.isEmpty()) { - if (path == currentPlaylistPath) + /* don't break early here since we want to make sure we've found both initial and current items if they exist */ + if (!foundInitial && path == initialPlaylist) { - found = true; + foundInitial = true; + initialItem = item; + } + if (!foundCurrent && !currentPlaylistPath.isEmpty() && path == currentPlaylistPath) + { + foundCurrent = true; m_listWidget->setCurrentItem(item); - break; } } } } - /* the previous playlist must be gone now, just select the first one */ - if (!found) - m_listWidget->setCurrentItem(firstItem); + if (!foundCurrent) + { + if (foundInitial && initialItem) + { + m_listWidget->setCurrentItem(initialItem); + } + else + { + /* the previous playlist must be gone now, just select the first one */ + m_listWidget->setCurrentItem(firstItem); + } + } } } } diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 9e64b80a69..5e0f65693a 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -581,6 +581,17 @@ MainWindow::~MainWindow() removeGridItems(); } +QString MainWindow::getSpecialPlaylistPath(SpecialPlaylist playlist) +{ + switch (playlist) + { + case SPECIAL_PLAYLIST_HISTORY: + return m_historyPlaylistsItem->data(Qt::UserRole).toString(); + default: + return QString(); + } +} + double MainWindow::lerp(double x, double y, double a, double b, double d) { return a + (b - a) * ((double)(d - x) / (double)(y - x)); } diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index e17954bf5a..16d49d632e 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -260,6 +260,9 @@ static void* ui_companion_qt_init(void) QComboBox *launchWithComboBox = NULL; QSettings *qsettings = NULL; QListWidget *listWidget = NULL; + QString initialPlaylist; + bool foundPlaylist = false; + int i = 0; if (!handle) @@ -275,6 +278,8 @@ static void* ui_companion_qt_init(void) qsettings = mainwindow->settings(); + initialPlaylist = qsettings->value("initial_playlist", mainwindow->getSpecialPlaylistPath(SPECIAL_PLAYLIST_HISTORY)).toString(); + mainwindow->resize(qMin(desktopRect.width(), INITIAL_WIDTH), qMin(desktopRect.height(), INITIAL_HEIGHT)); mainwindow->setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, mainwindow->size(), desktopRect)); @@ -571,16 +576,40 @@ static void* ui_companion_qt_init(void) mainwindow->onTabWidgetIndexChanged(0); } - for (i = 0; i < listWidget->count() && listWidget->count() > 0; i++) + /* the initial playlist that is selected is based on the user's setting (initialPlaylist) */ + for (i = 0; listWidget->count() && i < listWidget->count(); i++) { - /* select the first non-hidden row */ - if (!listWidget->isRowHidden(i)) + QListWidgetItem *item = listWidget->item(i); + QString path; + + if (!item) + continue; + + path = item->data(Qt::UserRole).toString(); + + if (path == initialPlaylist) { + foundPlaylist = true; + listWidget->setRowHidden(i, false); listWidget->setCurrentRow(i); break; } } + /* couldn't find the user's initial playlist, just find anything */ + if (!foundPlaylist) + { + for (i = 0; listWidget->count() && i < listWidget->count(); i++) + { + /* select the first non-hidden row */ + if (!listWidget->isRowHidden(i)) + { + listWidget->setCurrentRow(i); + break; + } + } + } + return handle; } diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 0b8debb3b9..f3703a499d 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -87,6 +87,11 @@ class CoreInfoDialog; class PlaylistEntryDialog; class ViewOptionsDialog; +enum SpecialPlaylist +{ + SPECIAL_PLAYLIST_HISTORY +}; + class GridItem : public QObject { Q_OBJECT @@ -277,6 +282,7 @@ public: QString getCurrentPlaylistPath(); QHash getCurrentContentHash(); static double lerp(double x, double y, double a, double b, double d); + QString getSpecialPlaylistPath(SpecialPlaylist playlist); signals: void thumbnailChanged(const QPixmap &pixmap); From 052424ffd22e90708eec607ebef357ed1248b56b Mon Sep 17 00:00:00 2001 From: Alfrix Date: Tue, 21 Aug 2018 15:27:25 -0300 Subject: [PATCH 122/182] Update Spanish --- intl/msg_hash_es.h | 10956 ++++++++++++++++++++++--------------------- 1 file changed, 5574 insertions(+), 5382 deletions(-) diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index d90679a1cf..ff2f1a139d 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -1,7176 +1,7368 @@ MSG_HASH( - MSG_COMPILER, - "Compilador" - ) + MSG_COMPILER, + "Compilador" + ) MSG_HASH( - MSG_UNKNOWN_COMPILER, - "Compilador Desconocido" - ) + MSG_UNKNOWN_COMPILER, + "Compilador Desconocido" + ) MSG_HASH( - MSG_DEVICE_DISCONNECTED_FROM_PORT, - "Dispositivo desconectado del puerto" - ) + MSG_DEVICE_DISCONNECTED_FROM_PORT, + "Dispositivo desconectado del puerto" + ) MSG_HASH( - MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, - "Recibido un comando de juego en red desconocido" - ) + MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, + "Recibido un comando de juego en red desconocido" + ) MSG_HASH( - MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, - "El archivo ya existe. Guardándolo en el búfer de respaldo" - ) + MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, + "El archivo ya existe. Guardándolo en el búfer de respaldo" + ) MSG_HASH( - MSG_GOT_CONNECTION_FROM, - "Conexión obtenida de: \"%s\"" - ) + MSG_GOT_CONNECTION_FROM, + "Conexión obtenida de: \"%s\"" + ) MSG_HASH( - MSG_GOT_CONNECTION_FROM_NAME, - "Conexión obtenida de: \"%s (%s)\"" - ) + MSG_GOT_CONNECTION_FROM_NAME, + "Conexión obtenida de: \"%s (%s)\"" + ) MSG_HASH( - MSG_PUBLIC_ADDRESS, - "Dirección pública" - ) + MSG_PUBLIC_ADDRESS, + "Dirección pública" + ) MSG_HASH( - MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, - "No se pasaron argumentos y no hay menú integrado, Mostrando ayuda..." - ) + MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, + "No se pasaron argumentos y no hay menú integrado, Mostrando ayuda..." + ) MSG_HASH( - MSG_SETTING_DISK_IN_TRAY, - "Poniendo disco en bandeja" - ) + MSG_SETTING_DISK_IN_TRAY, + "Poniendo disco en bandeja" + ) MSG_HASH( - MSG_WAITING_FOR_CLIENT, - "Esperando al cliente..." - ) + MSG_WAITING_FOR_CLIENT, + "Esperando al cliente..." + ) MSG_HASH( - MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME, - "As dejado el juego" - ) + MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME, + "As dejado el juego" + ) MSG_HASH( - MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, - "Unido como jugador %u" - ) + MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, + "Unido como jugador %u" + ) MSG_HASH( - MSG_NETPLAY_YOU_HAVE_JOINED_WITH_INPUT_DEVICES_S, - "Se ha unido con el dispositivo de entrada %.*s" - ) + MSG_NETPLAY_YOU_HAVE_JOINED_WITH_INPUT_DEVICES_S, + "Se ha unido con el dispositivo de entrada %.*s" + ) MSG_HASH( - MSG_NETPLAY_PLAYER_S_LEFT, - "Jugador %.*s dejó el juego" - ) + MSG_NETPLAY_PLAYER_S_LEFT, + "Jugador %.*s dejó el juego" + ) MSG_HASH( - MSG_NETPLAY_S_HAS_JOINED_AS_PLAYER_N, - "%.*s se ha unido como jugador %u" - ) + MSG_NETPLAY_S_HAS_JOINED_AS_PLAYER_N, + "%.*s se ha unido como jugador %u" + ) MSG_HASH( - MSG_NETPLAY_S_HAS_JOINED_WITH_INPUT_DEVICES_S, - "%.*s se ha unido con los dispositivos de entrada %.*s" - ) + MSG_NETPLAY_S_HAS_JOINED_WITH_INPUT_DEVICES_S, + "%.*s se ha unido con los dispositivos de entrada %.*s" + ) MSG_HASH( - MSG_NETPLAY_NOT_RETROARCH, - "Una conexión de netplay falló, probablemente no este usando RetroArch o esté usando una versión antigua de RetroArch" - ) + MSG_NETPLAY_NOT_RETROARCH, + "Una conexión de netplay falló, probablemente no este usando RetroArch o esté usando una versión antigua de RetroArch" + ) MSG_HASH( - MSG_NETPLAY_OUT_OF_DATE, - "El par de netplay esta usando una versión antigua de RetroArch. No se puede conectar" - ) + MSG_NETPLAY_OUT_OF_DATE, + "El par de netplay esta usando una versión antigua de RetroArch. No se puede conectar" + ) MSG_HASH( - MSG_NETPLAY_DIFFERENT_VERSIONS, - "ADVERTENCIA: Un par de netplay esta usando una versión diferente de Retroarch. Si ocurren problemas, use la misma versión" - ) + MSG_NETPLAY_DIFFERENT_VERSIONS, + "ADVERTENCIA: Un par de netplay esta usando una versión diferente de Retroarch. Si ocurren problemas, use la misma versión" + ) MSG_HASH( - MSG_NETPLAY_DIFFERENT_CORES, - "Un par de netplay esta usando una versión diferente del núcleo. No se puede conectar" - ) + MSG_NETPLAY_DIFFERENT_CORES, + "Un par de netplay esta usando una versión diferente del núcleo. No se puede conectar" + ) MSG_HASH( - MSG_NETPLAY_DIFFERENT_CORE_VERSIONS, - "ADVERTENCIA: Un par de netplay está ejecutando una versión diferente del núcleo. Si ocurren problemas, use la misma versión" - ) + MSG_NETPLAY_DIFFERENT_CORE_VERSIONS, + "ADVERTENCIA: Un par de netplay está ejecutando una versión diferente del núcleo. Si ocurren problemas, use la misma versión" + ) MSG_HASH( - MSG_NETPLAY_ENDIAN_DEPENDENT, - "Este núcleo no soporta juego en red entre diferentes arquitecturas de sistemas" - ) + MSG_NETPLAY_ENDIAN_DEPENDENT, + "Este núcleo no soporta juego en red entre diferentes arquitecturas de sistemas" + ) MSG_HASH( - MSG_NETPLAY_PLATFORM_DEPENDENT, - "Este núcleo no soporta juego en red entre diferentes sistemas" - ) + MSG_NETPLAY_PLATFORM_DEPENDENT, + "Este núcleo no soporta juego en red entre diferentes sistemas" + ) MSG_HASH( - MSG_NETPLAY_ENTER_PASSWORD, - "Introducir la contraseña del servidor de juego en red:" - ) + MSG_NETPLAY_ENTER_PASSWORD, + "Introducir la contraseña del servidor de juego en red:" + ) MSG_HASH( - MSG_NETPLAY_INCORRECT_PASSWORD, - "Contraseña incorrecta" - ) + MSG_NETPLAY_INCORRECT_PASSWORD, + "Contraseña incorrecta" + ) MSG_HASH( - MSG_NETPLAY_SERVER_NAMED_HANGUP, - "\"%s\" se ha desconectado" - ) + MSG_NETPLAY_SERVER_NAMED_HANGUP, + "\"%s\" se ha desconectado" + ) MSG_HASH( - MSG_NETPLAY_SERVER_HANGUP, - "Un cliente de juego en red se ha desconectado" - ) + MSG_NETPLAY_SERVER_HANGUP, + "Un cliente de juego en red se ha desconectado" + ) MSG_HASH( - MSG_NETPLAY_CLIENT_HANGUP, - "Desconectado del juego en red" - ) + MSG_NETPLAY_CLIENT_HANGUP, + "Desconectado del juego en red" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, - "No tienes permiso para jugar" - ) + MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, + "No tienes permiso para jugar" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, - "No hay lugar disponible" - ) + MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, + "No hay lugar disponible" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY_NOT_AVAILABLE, - "El dispositivo de entrada pedido no esta disponible" - ) + MSG_NETPLAY_CANNOT_PLAY_NOT_AVAILABLE, + "El dispositivo de entrada pedido no esta disponible" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY, - "No se puede cambiar al modo juego" - ) + MSG_NETPLAY_CANNOT_PLAY, + "No se puede cambiar al modo juego" + ) MSG_HASH( - MSG_NETPLAY_PEER_PAUSED, - "Cliente de juego en red \"%s\" pausado" - ) + MSG_NETPLAY_PEER_PAUSED, + "Cliente de juego en red \"%s\" pausado" + ) MSG_HASH( - MSG_NETPLAY_CHANGED_NICK, - "Tu apodo cambió a \"%s\"" - ) + MSG_NETPLAY_CHANGED_NICK, + "Tu apodo cambió a \"%s\"" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, - "Dar a los núcleos renderizados por hardware un contexto privado. Evita tener que asumir cambios en el estado del hardware entre cuadros" - ) + MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, + "Dar a los núcleos renderizados por hardware un contexto privado. Evita tener que asumir cambios en el estado del hardware entre cuadros" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SETTINGS, - "Ajusta la apariencia del menú" - ) + MENU_ENUM_SUBLABEL_MENU_SETTINGS, + "Ajusta la apariencia del menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, - "Fuerza la Sincronía de CPU y GPU. Reduce la latencia a costa del rendimiento" - ) + MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, + "Fuerza la Sincronía de CPU y GPU. Reduce la latencia a costa del rendimiento" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_THREADED, - "Mejora el rendimiento a costa de la latencia y posiblemente algunos tirones. Usar solo si no puede obtener máxima velocidad de otra manera" - ) + MENU_ENUM_SUBLABEL_VIDEO_THREADED, + "Mejora el rendimiento a costa de la latencia y posiblemente algunos tirones. Usar solo si no puede obtener máxima velocidad de otra manera" + ) MSG_HASH( - MSG_AUDIO_VOLUME, - "Volumen de Audio" - ) + MSG_AUDIO_VOLUME, + "Volumen de Audio" + ) MSG_HASH( - MSG_AUTODETECT, - "Auto-detectar" - ) + MSG_AUTODETECT, + "Auto-detectar" + ) MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Auto-cargar guardado rápido desde" - ) + MSG_AUTOLOADING_SAVESTATE_FROM, + "Auto-cargar guardado rápido desde" + ) MSG_HASH( - MSG_CAPABILITIES, - "Capacidades" - ) + MSG_CAPABILITIES, + "Capacidades" + ) MSG_HASH( - MSG_CONNECTING_TO_NETPLAY_HOST, - "Conectando al servidor de juego en red" - ) + MSG_CONNECTING_TO_NETPLAY_HOST, + "Conectando al servidor de juego en red" + ) MSG_HASH( - MSG_CONNECTING_TO_PORT, - "Conectando al puerto" - ) + MSG_CONNECTING_TO_PORT, + "Conectando al puerto" + ) MSG_HASH( - MSG_CONNECTION_SLOT, - "Lugar de conexión" - ) + MSG_CONNECTION_SLOT, + "Lugar de conexión" + ) MSG_HASH( - MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, - "Lo sentimos, no implementado: los núcleos que no requieren contenido no pueden participar en juego en red" - ) + MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, + "Lo sentimos, no implementado: los núcleos que no requieren contenido no pueden participar en juego en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, - "Contraseña" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, + "Contraseña" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, - "Cuenta de logros" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, + "Cuenta de logros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, - "Nombre de usuario" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, + "Nombre de usuario" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, - "Cuentas" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, + "Cuentas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, - "Fin de la lista" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, + "Fin de la lista" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, - "RetroAchievements" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, + "RetroAchievements" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, - "Lista de logros" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, + "Lista de logros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE, - "Pausar Modo Hardcore de logros" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE, + "Pausar Modo Hardcore de logros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME, - "Continuar usando el modo Hardcore de logros" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME, + "Continuar usando el modo Hardcore de logros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "Lista de logros (Hardcore)" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, + "Lista de logros (Hardcore)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, - "Escanear Contenido" - ) + MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, + "Escanear Contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, - "Configuraciones" - ) + MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, + "Configuraciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_TAB, - "Importar contenido" - ) + MENU_ENUM_LABEL_VALUE_ADD_TAB, + "Importar contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, - "Salas de juego en red" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, + "Salas de juego en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, - "Preguntar" - ) + MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, + "Preguntar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, - "Recursos" - ) + MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, + "Recursos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, - "Bloquear frames" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, + "Bloquear frames" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, - "Dispositivo de audio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, + "Dispositivo de audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, - "Controlador de Audio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, + "Controlador de Audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, - "Audio DSP plugin" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, + "Audio DSP plugin" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, - "Activar audio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, + "Activar audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, - "Filtro de audio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, + "Filtro de audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, - "Turbo/Zona Muerta" - ) + MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, + "Turbo/Zona Muerta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, - "Latencia de audio (ms)" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, + "Latencia de audio (ms)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, - "Variación máxima de sincronía de audio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, + "Variación máxima de sincronía de audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, - "Silenciar audio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, + "Silenciar audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, - "Frecuencia de muestreo de audio (Hz)" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, + "Frecuencia de muestreo de audio (Hz)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, - "Control de frecuencia dinámico" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, + "Control de frecuencia dinámico" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, - "Controlador de muestreo de audio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, + "Controlador de muestreo de audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, - "Audio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, + "Audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, - "Sincronía de audio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, + "Sincronía de audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, - "Volumen de Audio (dB)" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, + "Volumen de Audio (dB)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_EXCLUSIVE_MODE, - "WASAPI Mode Exclusivo" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_EXCLUSIVE_MODE, + "WASAPI Mode Exclusivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_FLOAT_FORMAT, - "WASAPI Formato de coma flotante" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_FLOAT_FORMAT, + "WASAPI Formato de coma flotante" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_SH_BUFFER_LENGTH, - "WASAPI Tamaño del búfer compartido" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_SH_BUFFER_LENGTH, + "WASAPI Tamaño del búfer compartido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, - "Intervalo de auto-guardado SaveRAM" - ) + MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, + "Intervalo de auto-guardado SaveRAM" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, - "Cargar autom. archivos de personalización" - ) + MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, + "Cargar autom. archivos de personalización" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, - "Cargar autom. archivos de re-mapeo" - ) + MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, + "Cargar autom. archivos de re-mapeo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, - "Cargar Shaders automáticamente" - ) + MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, + "Cargar Shaders automáticamente" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, - "Atrás" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, + "Atrás" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, - "Confirmar" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, + "Confirmar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, - "Información" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, + "Información" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, - "Salir" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, + "Salir" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, - "Desplazar hacia abajo" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, + "Desplazar hacia abajo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, - "Desplazar hacia arriba" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, + "Desplazar hacia arriba" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, - "Iniciar" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, + "Iniciar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, - "Mostrar teclado" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, + "Mostrar teclado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, - "Mostrar menú" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, + "Mostrar menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, - "Controles básicos del menú" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, + "Controles básicos del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, - "Confirmar" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, + "Confirmar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, - "Información" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, + "Información" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, - "Salir" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, + "Salir" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, - "Desplazar hacia arriba" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, + "Desplazar hacia arriba" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, - "Valores predeterminados" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, + "Valores predeterminados" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_KEYBOARD, - "Mostrar teclado" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_KEYBOARD, + "Mostrar teclado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, - "Mostrar menú" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, + "Mostrar menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, - "No sobrescribir SaveRAM al cargar un guardado rápido" - ) + MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, + "No sobrescribir SaveRAM al cargar un guardado rápido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, - "Activar Bluetooth" - ) + MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, + "Activar Bluetooth" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, - "URL de recursos del Buildbot" - ) + MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, + "URL de recursos del Buildbot" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, - "Caché" - ) + MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, + "Caché" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, - "Permitir cámara" - ) + MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, + "Permitir cámara" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, - "Controlador de cámara" - ) + MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, + "Controlador de cámara" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT, - "Truco" - ) + MENU_ENUM_LABEL_VALUE_CHEAT, + "Truco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, - "Aplicar trucos" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, + "Aplicar trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_START_SEARCH, - "Iniciar búsqueda de trucos" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_START_SEARCH, + "Iniciar búsqueda de trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_CONTINUE_SEARCH, - "Continuar búsqueda" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_CONTINUE_SEARCH, + "Continuar búsqueda" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, - "Archivo de trucos" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, + "Archivo de trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE, - "Archivo de trucos" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_FILE, + "Archivo de trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, - "Cargar archivo de trucos (Reemplazar)" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, + "Cargar archivo de trucos (Reemplazar)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD_APPEND, - "Cargar archivo de trucos (Agregar)" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD_APPEND, + "Cargar archivo de trucos (Agregar)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, - "Guardar archivo de trucos como" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, + "Guardar archivo de trucos como" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, - "Pasadas de trucos" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, + "Pasadas de trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, - "Descripción" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, + "Descripción" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, - "Logros en modo Hardcore" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, + "Logros en modo Hardcore" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_LEADERBOARDS_ENABLE, - "Tablas de clasificación" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_LEADERBOARDS_ENABLE, + "Tablas de clasificación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_BADGES_ENABLE, - "Insignias de logros" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_BADGES_ENABLE, + "Insignias de logros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, - "Logros bloqueados:" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, + "Logros bloqueados:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY, - "Bloqueado" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY, + "Bloqueado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_SETTINGS, - "RetroAchievements" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_SETTINGS, + "RetroAchievements" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, - "Probar logros No oficiales" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, + "Probar logros No oficiales" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, - "Logros desbloqueados:" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, + "Logros desbloqueados:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY, - "Desbloqueado" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY, + "Desbloqueado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, - "Hardcore" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, + "Hardcore" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_VERBOSE_ENABLE, - "Logros modo informativo" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_VERBOSE_ENABLE, + "Logros modo informativo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_AUTO_SCREENSHOT, - "Captura de pantalla automatica" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_AUTO_SCREENSHOT, + "Captura de pantalla automatica" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, - "Cerrar" - ) + MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, + "Cerrar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIG, - "Config" - ) + MENU_ENUM_LABEL_VALUE_CONFIG, + "Config" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, - "Cargar configuración" - ) + MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, + "Cargar configuración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, - "Configuración" - ) + MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, + "Configuración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, - "Guardar configuración al salir" - ) + MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, + "Guardar configuración al salir" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST, - "Colecciones" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST, + "Colecciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, - "Base de datos" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, + "Base de datos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_DIR, - "Contenido" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_DIR, + "Contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, - "Tamaño del historial" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, + "Tamaño del historial" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, - "Permitir quitar entradas" - ) + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, + "Permitir quitar entradas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, - "Menú rápido" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, + "Menú rápido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, - "Descargas" - ) + MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, + "Descargas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, - "Descargas" - ) + MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, + "Descargas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, - "Trucos" - ) + MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, + "Trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, - "Contadores de núcleo" - ) + MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, + "Contadores de núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_ENABLE, - "Mostrar nombre del núcleo" - ) + MENU_ENUM_LABEL_VALUE_CORE_ENABLE, + "Mostrar nombre del núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, - "Información del núcleo" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, + "Información del núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, - "Autores" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, + "Autores" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, - "Categorías" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, + "Categorías" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL, - "Etiqueta del núcleo" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL, + "Etiqueta del núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME, - "Nombre del núcleo" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME, + "Nombre del núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, - "Firmware(s)" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, + "Firmware(s)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, - "Licencia(s)" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, + "Licencia(s)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, - "Permisos" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, + "Permisos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS, - "Extensiones compatibles" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS, + "Extensiones compatibles" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_MANUFACTURER, - "Fabricante del sistema" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_MANUFACTURER, + "Fabricante del sistema" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, - "Nombre del sistema" - ) + MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, + "Nombre del sistema" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, - "Controles" - ) + MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, + "Controles" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_LIST, - "Cargar núcleo" - ) + MENU_ENUM_LABEL_VALUE_CORE_LIST, + "Cargar núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, - "Opciones" - ) + MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, + "Opciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_SETTINGS, - "Núcleo" - ) + MENU_ENUM_LABEL_VALUE_CORE_SETTINGS, + "Núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_SET_SUPPORTS_NO_CONTENT_ENABLE, - "Iniciar un núcleo automáticamente" - ) + MENU_ENUM_LABEL_VALUE_CORE_SET_SUPPORTS_NO_CONTENT_ENABLE, + "Iniciar un núcleo automáticamente" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, - "Extraer automáticamente el archivo descargado" - ) + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Extraer automáticamente el archivo descargado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, - "URL de núcleos de Buildbot" - ) + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, + "URL de núcleos de Buildbot" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST, - "Actualizador de núcleos" - ) + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST, + "Actualizador de núcleos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, - "Actualizador" - ) + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, + "Actualizador" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CPU_ARCHITECTURE, - "Arquitectura de CPU:" - ) + MENU_ENUM_LABEL_VALUE_CPU_ARCHITECTURE, + "Arquitectura de CPU:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CPU_CORES, - "Núcleos de CPU:" - ) + MENU_ENUM_LABEL_VALUE_CPU_CORES, + "Núcleos de CPU:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CURSOR_DIRECTORY, - "Cursor" - ) + MENU_ENUM_LABEL_VALUE_CURSOR_DIRECTORY, + "Cursor" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CURSOR_MANAGER, - "Gestor de cursores" - ) + MENU_ENUM_LABEL_VALUE_CURSOR_MANAGER, + "Gestor de cursores" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO, - "Relación personalizada" - ) + MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO, + "Relación personalizada" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER, - "Gestor de bases de datos" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER, + "Gestor de bases de datos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_SELECTION, - "Seleccionar bases de datos" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_SELECTION, + "Seleccionar bases de datos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DELETE_ENTRY, - "Quitar" - ) + MENU_ENUM_LABEL_VALUE_DELETE_ENTRY, + "Quitar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FAVORITES, - "Favoritos" - ) + MENU_ENUM_LABEL_VALUE_FAVORITES, + "Favoritos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, - "" - ) + MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, + "" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, - "" - ) + MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, + "" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE, - "" - ) + MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE, + "" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, - "No se ha encontrado la carpeta" - ) + MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, + "No se ha encontrado la carpeta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS, - "Carpetas" - ) + MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS, + "Carpetas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS, - "Estado de la bandeja de discos" - ) + MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS, + "Estado de la bandeja de discos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, - "Asignar imagen de disco" - ) + MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, + "Asignar imagen de disco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISK_INDEX, - "Índice de disco" - ) + MENU_ENUM_LABEL_VALUE_DISK_INDEX, + "Índice de disco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, - "Control de disco" - ) + MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, + "Control de disco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DONT_CARE, - "No importa" - ) + MENU_ENUM_LABEL_VALUE_DONT_CARE, + "No importa" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, - "Descargas" - ) + MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, + "Descargas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE, - "Descargar núcleo" - ) + MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE, + "Descargar núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT, - "Descargador de contenido" - ) + MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT, + "Descargador de contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_ENABLE, - "Forzar DPI" - ) + MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_ENABLE, + "Forzar DPI" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_VALUE, - "Anular DPI" - ) + MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_VALUE, + "Anular DPI" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, - "Controladores" - ) + MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, + "Controladores" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, - "Cargar vacío al cerrar núcleo" - ) + MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, + "Cargar vacío al cerrar núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, - "Chequear si falta Firmware antes de cargar" - ) + MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, + "Chequear si falta Firmware antes de cargar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, - "Fondo de pantalla dinámico" - ) + MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, + "Fondo de pantalla dinámico" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, - "Fondos de pantalla dinámicos" - ) + MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, + "Fondos de pantalla dinámicos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, - "Activar logros" - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, + "Activar logros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, - "Color de resaltado del menú" - ) + MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, + "Color de resaltado del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, - "Color normal del menú" - ) + MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, + "Color normal del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FALSE, - "Desactivado" - ) + MENU_ENUM_LABEL_VALUE_FALSE, + "Desactivado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, - "Velocidad máxima de ejecución" - ) + MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, + "Velocidad máxima de ejecución" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, - "Favoritos" - ) + MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, + "Favoritos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FPS_SHOW, - "Mostrar FPS" - ) + MENU_ENUM_LABEL_VALUE_FPS_SHOW, + "Mostrar FPS" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, - "Limitar velocidad máxima de ejecución" - ) + MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, + "Limitar velocidad máxima de ejecución" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, - "Velocidad de frames" - ) + MENU_ENUM_LABEL_VALUE_VRR_RUNLOOP_ENABLE, + "Sincronizar pantalla al contenido (G-Sync, FreeSync)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, - "Contadores de la interfaz" - ) + MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, + "Velocidad de frames" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, - "Usar opciones de núcleo para cada juego si existen" - ) + MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, + "Contadores de la interfaz" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, - "Crear archivo de opciones del juego" - ) + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, + "Usar opciones de núcleo para cada juego si existen" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, - "Archivo de opciones del juego" - ) + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, + "Crear archivo de opciones del juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HELP, - "Ayuda" - ) + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, + "Archivo de opciones del juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, - "Solucionar problemas de Audio/Video" - ) + MENU_ENUM_LABEL_VALUE_HELP, + "Ayuda" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, - "Cambiar el mando virtual superpuesto" - ) + MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, + "Solucionar problemas de Audio/Video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, - "Controles básicos del menú" - ) + MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, + "Cambiar el mando virtual superpuesto" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HELP_LIST, - "Ayuda" - ) + MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, + "Controles básicos del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, - "Cargando contenido" - ) + MENU_ENUM_LABEL_VALUE_HELP_LIST, + "Ayuda" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, - "Buscando contenido" - ) + MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, + "Cargando contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, - "¿Qué es un núcleo?" - ) + MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, + "Buscando contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, - "Activar Historial" - ) + MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, + "¿Qué es un núcleo?" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HISTORY_TAB, - "Historial" - ) + MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, + "Activar Historial" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, - "Menú Horizontal" - ) + MENU_ENUM_LABEL_VALUE_HISTORY_TAB, + "Historial" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_IMAGES_TAB, - "Imágenes" - ) + MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, + "Menú Horizontal" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INFORMATION, - "Información" - ) + MENU_ENUM_LABEL_VALUE_IMAGES_TAB, + "Imágenes" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, - "Información" - ) + MENU_ENUM_LABEL_VALUE_INFORMATION, + "Información" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, - "Tipo de analógico a digital" - ) + MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, + "Información" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, - "Todos controlan el menú" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, + "Tipo de analógico a digital" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, - "Analógico izq. X" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, + "Todos controlan el menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, - "Analógico izq. X- (IZQUIERDA)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, + "Analógico izq. X" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, - "Analógico izq. X+ (DERECHA)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, + "Analógico izq. X- (IZQUIERDA)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y, - "Analógico izq. Y" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, + "Analógico izq. X+ (DERECHA)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, - "Analógico izq. Y- (ARRIBA)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y, + "Analógico izq. Y" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, - "Analógico izq. Y+ (ABAJO)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, + "Analógico izq. Y- (ARRIBA)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X, - "Analógico der. X" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, + "Analógico izq. Y+ (ABAJO)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, - "Analógico der. X- (IZQUIERDA)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X, + "Analógico der. X" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, - "Analógico der. X+ (DERECHA)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, + "Analógico der. X- (IZQUIERDA)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y, - "Analógico der. Y" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, + "Analógico der. X+ (DERECHA)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, - "Analógico der. Y- (ARRIBA)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y, + "Analógico der. Y" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, - "Analógico der. Y+ (ABAJO)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, + "Analógico der. Y- (ARRIBA)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, - "Arma: Gatillo" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, + "Analógico der. Y+ (ABAJO)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, - "Arma: Recargar" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, + "Arma: Gatillo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A, - "Arma: Aux A" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, + "Arma: Recargar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B, - "Arma: Aux B" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A, + "Arma: Aux A" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C, - "Arma: Aux C" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B, + "Arma: Aux B" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START, - "Arma: Start" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C, + "Arma: Aux C" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT, - "Arma: Select" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START, + "Arma: Start" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP, - "Arma: D-pad ARRIBA" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT, + "Arma: Select" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN, - "Arma: D-pad ABAJO" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP, + "Arma: D-pad ARRIBA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT, - "Arma: D-pad IZQUIERDA" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN, + "Arma: D-pad ABAJO" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, - "Arma: D-pad DERECHA" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT, + "Arma: D-pad IZQUIERDA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, - "Activar Auto-configuración" - ) + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, + "Arma: D-pad DERECHA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, - "Zona muerta analógica" - ) + MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, + "Activar Auto-configuración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, - "Menú: cambiar OK y Cancelar" - ) + MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, + "Zona muerta analógica" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, - "Asignar todo" - ) + MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, + "Menú: cambiar OK y Cancelar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, - "Asignar valores por defecto" - ) + MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, + "Asignar todo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_BIND_TIMEOUT, - "Tiempo limite para asignar" - ) + MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, + "Asignar valores por defecto" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_BIND_HOLD, - "Asignar (mantener)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_BIND_TIMEOUT, + "Tiempo limite para asignar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_HIDE_UNBOUND, - "Ocultar descripciones de entrada sin asignar de los núcleo" - ) + MENU_ENUM_LABEL_VALUE_INPUT_BIND_HOLD, + "Asignar (mantener)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW, - "Mostrar etiquetas de descripción de entrada" - ) + MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_HIDE_UNBOUND, + "Ocultar descripciones de entrada sin asignar de los núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, - "Indice de dispositivo" - ) + MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW, + "Mostrar etiquetas de descripción de entrada" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, - "Tipo de dispositivo" - ) + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, + "Indice de dispositivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, - "Indice de ratón" - ) + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, + "Tipo de dispositivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DRIVER, - "Controlador de entrada" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, + "Indice de ratón" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Ciclo de trabajo" - ) + MENU_ENUM_LABEL_VALUE_INPUT_DRIVER, + "Controlador de entrada" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, - "Asignar Hotkeys" - ) + MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + "Ciclo de trabajo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, - "Activar mapeo de Teclado-Mando" - ) + MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, + "Asignar Hotkeys" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, - "Botón A (DERECHA)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, + "Activar mapeo de Teclado-Mando" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, - "Botón B (ABAJO)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, + "Botón A (DERECHA)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, - "D-pad ABAJO" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, + "Botón B (ABAJO)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, - "Botón L2 (LT)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, + "D-pad ABAJO" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, - "Botón L3 (Pulsar analógico IZQ.)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, + "Botón L2 (LT)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, - "Botón L1 (LB)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, + "Botón L3 (Pulsar analógico IZQ.)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, - "D-pad IZQUIERDA" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, + "Botón L1 (LB)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, - "Botón R2 (RT)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, + "D-pad IZQUIERDA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, - "Botón R3 (Pulsar analógico DER.)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, + "Botón R2 (RT)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, - "Botón R1 (RB)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, + "Botón R3 (Pulsar analógico DER.)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, - "D-pad DERECHA" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, + "Botón R1 (RB)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, - "Botón Select" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, + "D-pad DERECHA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, - "Botón Start" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, + "Botón Select" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, - "D-pad ARRIBA" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, + "Botón Start" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, - "Botón X (ARRIBA)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, + "D-pad ARRIBA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, - "Botón Y (IZQUIERDA)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, + "Botón X (ARRIBA)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_KEY, - "(Tecla: %s)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, + "Botón Y (IZQUIERDA)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_LEFT, - "Ratón 1" - ) + MENU_ENUM_LABEL_VALUE_INPUT_KEY, + "(Tecla: %s)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_RIGHT, - "Ratón 2" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_LEFT, + "Ratón 1" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_MIDDLE, - "Ratón 3" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_RIGHT, + "Ratón 2" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON4, - "Ratón 4" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_MIDDLE, + "Ratón 3" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON5, - "Ratón 5" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON4, + "Ratón 4" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_UP, - "Rueda ARRIBA" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON5, + "Ratón 5" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_DOWN, - "Rueda ABAJO" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_UP, + "Rueda ARRIBA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_UP, - "Rueda IZQUIERDA" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_DOWN, + "Rueda ABAJO" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_DOWN, - "Rueda DERECHA" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_UP, + "Rueda IZQUIERDA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, - "Tipo de mapeo Teclado-Mando" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_DOWN, + "Rueda DERECHA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, - "Máximo de usuarios" - ) + MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, + "Tipo de mapeo Teclado-Mando" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Combinación para mostrar el menú" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, + "Máximo de usuarios" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, - "Indice de trucos -" - ) + MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, + "Combinación para mostrar el menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, - "Indice de trucos +" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, + "Indice de trucos -" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, - "Activar truco" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, + "Indice de trucos +" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, - "Expulsar disco" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, + "Activar truco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, - "Siguiente disco" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, + "Expulsar disco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, - "Disco previo" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, + "Siguiente disco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, - "Activar hotkeys" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, + "Disco previo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, - "Mantener para avance rápido" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, + "Activar hotkeys" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, - "Avance rápido" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, + "Mantener para avance rápido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, - "Avanzar frame" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, + "Avance rápido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, - "Pantalla completa" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, + "Avanzar frame" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, - "Capturar ratón" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, + "Pantalla completa" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, - "Game focus (desactivar hotkeys)" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, + "Capturar ratón" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, - "Activar menú de escritorio" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, + "Game focus (desactivar hotkeys)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, - "Cargar estado" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, + "Activar menú de escritorio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, - "Mostrar menú" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, + "Cargar estado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, - "Grabar video" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, + "Mostrar menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, - "Silenciar audio" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, + "Grabar video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, - "Juego en red: cambiar modo juego/espectador" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, + "Silenciar audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, - "Mostrar teclado en pantalla" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, + "Juego en red: cambiar modo juego/espectador" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, - "Siguiente superposición" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, + "Mostrar teclado en pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, - "Pausar" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, + "Siguiente superposición" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, - "Cerrar RetroArch" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, + "Pausar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, - "Resetear juego" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, + "Cerrar RetroArch" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, - "Rebobinar" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, + "Resetear juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, - "Guardar estado" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, + "Rebobinar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, - "Captura de pantalla" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_DETAILS, + "Detalles de truco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, - "Siguiente shader" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_SEARCH, + "Iniciar o continuar búsqueda de trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, - "Shader previo" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, + "Guardar estado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY, - "Tecla a mantener para cámara lenta" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, + "Captura de pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY, - "Activar Cámara lenta" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, + "Siguiente shader" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, - "Posición de guardado -" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, + "Shader previo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, - "Posición de guardado +" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY, + "Tecla a mantener para cámara lenta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, - "Volumen -" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY, + "Activar Cámara lenta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, - "Volumen +" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, + "Posición de guardado -" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, - "Mostrar superposición" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, + "Posición de guardado +" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, - "Ocultar superposición en el menú" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, + "Volumen -" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, - "Mostrar entradas en la superposición" - ) + MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, + "Volumen +" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, - "Puerto de escucha para entradas" - ) + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, + "Mostrar superposición" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, - "Comportamiento del sondeo" - ) + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, + "Ocultar superposición en el menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, - "Temprano" - ) + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Mostrar entradas en la superposición" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_LATE, - "Tarde" - ) + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Puerto de escucha para entradas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_NORMAL, - "Normal" - ) + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, + "Comportamiento del sondeo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_PREFER_FRONT_TOUCH, - "Preferir táctil frontal" - ) + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, + "Temprano" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, - "Reasignación de entrada" - ) + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_LATE, + "Tarde" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, - "Permitir reasignar controles" - ) + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_NORMAL, + "Normal" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, - "Guardar Auto-configuración" - ) + MENU_ENUM_LABEL_VALUE_INPUT_PREFER_FRONT_TOUCH, + "Preferir táctil frontal" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, - "Controles" - ) + MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, + "Reasignación de entrada" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, - "Activar teclado pequeño" - ) + MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, + "Permitir reasignar controles" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_ENABLE, - "Activar táctil" - ) + MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, + "Guardar Auto-configuración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "Activar turbo" - ) + MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, + "Controles" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, - "Periodo del turbo" - ) + MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, + "Activar teclado pequeño" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, - "Controles del usuario %u" - ) + MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_ENABLE, + "Activar táctil" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LATENCY_SETTINGS, - "Latencia" - ) + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Activar turbo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INTERNAL_STORAGE_STATUS, - "Estado del almacenamiento interno" - ) + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, + "Periodo del turbo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, - "Auto-configuración de controles" - ) + MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, + "Controles del usuario %u" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, - "Controlador de mando" - ) + MENU_ENUM_LABEL_VALUE_LATENCY_SETTINGS, + "Latencia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, - "Servicios" - ) + MENU_ENUM_LABEL_VALUE_INTERNAL_STORAGE_STATUS, + "Estado del almacenamiento interno" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_CHINESE_SIMPLIFIED, - "Chino (Simplificado)" - ) + MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, + "Auto-configuración de controles" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_CHINESE_TRADITIONAL, - "Chino (Tradicional)" - ) + MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, + "Controlador de mando" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_DUTCH, - "Holandés" - ) + MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, + "Servicios" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_ENGLISH, - "Ingles" - ) + MENU_ENUM_LABEL_VALUE_LANG_CHINESE_SIMPLIFIED, + "Chino (Simplificado)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_ESPERANTO, - "Esperanto" - ) + MENU_ENUM_LABEL_VALUE_LANG_CHINESE_TRADITIONAL, + "Chino (Tradicional)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_FRENCH, - "Francés" - ) + MENU_ENUM_LABEL_VALUE_LANG_DUTCH, + "Holandés" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_GERMAN, - "Alemán" - ) + MENU_ENUM_LABEL_VALUE_LANG_ENGLISH, + "Ingles" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_ITALIAN, - "Italiano" - ) + MENU_ENUM_LABEL_VALUE_LANG_ESPERANTO, + "Esperanto" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_JAPANESE, - "Japones" - ) + MENU_ENUM_LABEL_VALUE_LANG_FRENCH, + "Francés" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_KOREAN, - "Coreano" - ) + MENU_ENUM_LABEL_VALUE_LANG_GERMAN, + "Alemán" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_POLISH, - "Polaco" - ) + MENU_ENUM_LABEL_VALUE_LANG_ITALIAN, + "Italiano" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_BRAZIL, - "Portugués (Brasil)" - ) + MENU_ENUM_LABEL_VALUE_LANG_JAPANESE, + "Japones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_PORTUGAL, - "Portugués (Portugal)" - ) + MENU_ENUM_LABEL_VALUE_LANG_KOREAN, + "Coreano" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_RUSSIAN, - "Ruso" - ) + MENU_ENUM_LABEL_VALUE_LANG_POLISH, + "Polaco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_SPANISH, - "Español" - ) + MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_BRAZIL, + "Portugués (Brasil)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE, - "Vietnamita" - ) + MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_PORTUGAL, + "Portugués (Portugal)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LANG_ARABIC, - "Árabe" - ) + MENU_ENUM_LABEL_VALUE_LANG_RUSSIAN, + "Ruso" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, - "Analógico izquierdo" - ) + MENU_ENUM_LABEL_VALUE_LANG_SPANISH, + "Español" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, - "Núcleos" - ) + MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE, + "Vietnamita" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, - "Información de núcleos" - ) + MENU_ENUM_LABEL_VALUE_LANG_ARABIC, + "Árabe" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, - "Nivel de registro de los núcleos" - ) + MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, + "Analógico izquierdo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LINEAR, - "Lineal" - ) + MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, + "Núcleos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, - "Cargar archivo" - ) + MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, + "Información de núcleos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, - "Cargar archivos recientes" - ) + MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, + "Nivel de registro de los núcleos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, - "Cargar Contenido" - ) + MENU_ENUM_LABEL_VALUE_LINEAR, + "Lineal" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LOAD_STATE, - "Cargar rápida" - ) + MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, + "Cargar archivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, - "Permitir ubicación" - ) + MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, + "Cargar archivos recientes" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER, - "Controlador de ubicación" - ) + MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, + "Cargar Contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, - "Registros" - ) + MENU_ENUM_LABEL_VALUE_LOAD_STATE, + "Cargar rápida" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY, - "Verbosidad del registro" - ) + MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, + "Permitir ubicación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MAIN_MENU, - "Menú principal" - ) + MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER, + "Controlador de ubicación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MANAGEMENT, - "Ajustes de bases de datos" - ) + MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, + "Registros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, - "Tema de color del menú" - ) + MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY, + "Verbosidad del registro" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE, - "Azul" - ) + MENU_ENUM_LABEL_VALUE_MAIN_MENU, + "Menú principal" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, - "Azul gris" - ) + MENU_ENUM_LABEL_VALUE_MANAGEMENT, + "Ajustes de bases de datos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_DARK_BLUE, - "Azul obscuro" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, + "Tema de color del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GREEN, - "Verde" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE, + "Azul" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_NVIDIA_SHIELD, - "Shield" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, + "Azul gris" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_RED, - "Rojo" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_DARK_BLUE, + "Azul obscuro" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_YELLOW, - "Amarillo" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GREEN, + "Verde" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, - "Opacidad del pie de página" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_NVIDIA_SHIELD, + "Shield" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, - "Opacidad del encabezado" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_RED, + "Rojo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_DRIVER, - "Controlador del menú" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_YELLOW, + "Amarillo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, - "Controlar FPS del menú" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, + "Opacidad del pie de página" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, - "Configuraciones" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, + "Opacidad del encabezado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, - "Filtro lineal del menú" - ) + MENU_ENUM_LABEL_VALUE_MENU_DRIVER, + "Controlador del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, - "Animación horizontal" - ) + MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, + "Controlar FPS del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Apariencia" - ) + MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, + "Configuraciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, - "Fondo" - ) + MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, + "Filtro lineal del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, - "Opacidad del fondo" - ) + MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, + "Animación horizontal" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MISSING, - "Faltante" - ) + MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, + "Apariencia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MORE, - "..." - ) + MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, + "Fondo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MOUSE_ENABLE, - "Soporte para ratón" - ) + MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, + "Opacidad del fondo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MULTIMEDIA_SETTINGS, - "Multimedia" - ) + MENU_ENUM_LABEL_VALUE_MISSING, + "Faltante" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MUSIC_TAB, - "Música" - ) + MENU_ENUM_LABEL_VALUE_MORE, + "..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, - "Filtrar extensiones desconocidas" - ) + MENU_ENUM_LABEL_VALUE_MOUSE_ENABLE, + "Soporte para ratón" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, - "Volver al inicio al llegar al final" - ) + MENU_ENUM_LABEL_VALUE_MULTIMEDIA_SETTINGS, + "Multimedia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NEAREST, - "Mas cercano" - ) + MENU_ENUM_LABEL_VALUE_MUSIC_TAB, + "Música" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY, - "Juego en red" - ) + MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Filtrar extensiones desconocidas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_SLAVES, - "Permitir clientes en modo esclavo" - ) + MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, + "Volver al inicio al llegar al final" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, - "Juego en red: chequear frames" - ) + MENU_ENUM_LABEL_VALUE_NEAREST, + "Mas cercano" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, - "Latencia mínima en frames" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY, + "Juego en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, - "Rango de latencia en frames" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_SLAVES, + "Permitir clientes en modo esclavo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, - "Juego en red: retrasar frames" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, + "Juego en red: chequear frames" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, - "Desconectar del servidor" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Latencia mínima en frames" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, - "Activar juego en red" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "Rango de latencia en frames" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, - "Conectar a un servidor de juego" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, + "Juego en red: retrasar frames" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, - "Iniciar servidor de juego" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, + "Desconectar del servidor" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, - "Terminar juego en red" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, + "Activar juego en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, - "Dirección del servidor" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, + "Conectar a un servidor de juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, - "Escanear red local" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, + "Iniciar servidor de juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, - "Activar cliente de juego en red" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, + "Terminar juego en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, - "Apodo para juego en red" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, + "Dirección del servidor" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, - "Contraseña del servidor" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, + "Escanear red local" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, - "Anunciar juego en red públicamente" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, + "Activar cliente de juego en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_REQUEST_DEVICE_I, - "Pedir dispositivo %u" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, + "Apodo para juego en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_REQUIRE_SLAVES, - "Desactivar clientes sin modo esclavo" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, + "Contraseña del servidor" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, - "Configurar juego en red" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, + "Anunciar juego en red públicamente" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG, - "Comparir entrada analoga" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_REQUEST_DEVICE_I, + "Pedir dispositivo %u" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_MAX, - "Max" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_REQUIRE_SLAVES, + "Desactivar clientes sin modo esclavo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_AVERAGE, - "Promedio" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, + "Configurar juego en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL, - "Compartir entrada digital" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG, + "Comparir entrada analoga" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_OR, - "Compartir" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_MAX, + "Max" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_XOR, - "Grapple" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_AVERAGE, + "Promedio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_VOTE, - "Votar" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL, + "Compartir entrada digital" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NONE, - "Nada" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_OR, + "Compartir" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NO_PREFERENCE, - "Sin preferencia" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_XOR, + "Grapple" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_START_AS_SPECTATOR, - "Juego en red: modo espectador" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_VOTE, + "Votar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, - "Juego en red: modo sin estados" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NONE, + "Nada" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, - "Contraseña del servidor para espectadores" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NO_PREFERENCE, + "Sin preferencia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, - "Juego en red: activar espectadores" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_START_AS_SPECTATOR, + "Juego en red: modo espectador" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, - "Juego en red: Puerto TCP" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, + "Juego en red: modo sin estados" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, - "Juego en red: NAT Traversal" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, + "Contraseña del servidor para espectadores" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, - "Comandos de red" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, + "Juego en red: activar espectadores" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, - "Puerto de comandos de red" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, + "Juego en red: Puerto TCP" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION, - "Información de red" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, + "Juego en red: NAT Traversal" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, - "Mando en red" - ) + MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, + "Comandos de red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, - "Puerto de base remota de red" - ) + MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, + "Puerto de comandos de red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, - "Red" - ) + MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION, + "Información de red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO, - "No" - ) + MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, + "Mando en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NONE, - "Ninguno" - ) + MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, + "Puerto de base remota de red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE, - "No disponible" - ) + MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, + "Red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY, - "Sin logros que mostrar" - ) + MENU_ENUM_LABEL_VALUE_NO, + "No" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_CORE, - "Sin núcleo" - ) + MENU_ENUM_LABEL_VALUE_NONE, + "Ninguno" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, - "No hay núcleos disponibles" - ) + MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE, + "No disponible" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, - "No hay información del núcleo" - ) + MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY, + "Sin logros que mostrar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, - "No hay opciones del núcleo" - ) + MENU_ENUM_LABEL_VALUE_NO_CORE, + "Sin núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, - "No hay entradas disponibles" - ) + MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, + "No hay núcleos disponibles" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, - "No hay historial disponible" - ) + MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, + "No hay información del núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, - "No hay información disponible" - ) + MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, + "No hay opciones del núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_ITEMS, - "No hay elementos" - ) + MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, + "No hay entradas disponibles" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, - "No se encontraron anfitriones" - ) + MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, + "No hay historial disponible" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, - "No se encuentran redes" - ) + MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, + "No hay información disponible" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, - "No hay contadores de rendimiento" - ) + MENU_ENUM_LABEL_VALUE_NO_ITEMS, + "No hay elementos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, - "No hay listas de reproducción" - ) + MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, + "No se encontraron anfitriones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, - "No hay entradas en la lista de reproducción" - ) + MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, + "No se encuentran redes" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, - "No se ha encontrado una configuración" - ) + MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, + "No hay contadores de rendimiento" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, - "No hay parámetros de shaders" - ) + MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, + "No hay listas de reproducción" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_OFF, - "OFF" - ) + MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, + "No hay entradas en la lista de reproducción" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ON, - "ON" - ) + MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, + "No se ha encontrado una configuración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ONLINE, - "En línea" - ) + MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, + "No hay parámetros de shaders" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, - "Actualizador en línea" - ) + MENU_ENUM_LABEL_VALUE_OFF, + "OFF" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, - "Información en pantalla (OSD)" - ) + MENU_ENUM_LABEL_VALUE_ON, + "ON" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, - "Superposiciones" - ) + MENU_ENUM_LABEL_VALUE_ONLINE, + "En línea" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ONSCREEN_OVERLAY_SETTINGS, - "Opciones de controles en pantalla o marcos" - ) + MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, + "Actualizador en línea" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, - "Notificaciones" - ) + MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, + "Información en pantalla (OSD)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ONSCREEN_NOTIFICATIONS_SETTINGS, - "Ajusta las notificaciones en pantalla" - ) + MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, + "Superposiciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, - "Explorar archivo" - ) + MENU_ENUM_SUBLABEL_ONSCREEN_OVERLAY_SETTINGS, + "Opciones de controles en pantalla o marcos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_OPTIONAL, - "Opcional" - ) + MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, + "Notificaciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_OVERLAY, - "Superposiciones" - ) + MENU_ENUM_SUBLABEL_ONSCREEN_NOTIFICATIONS_SETTINGS, + "Ajusta las notificaciones en pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, - "Auto-cargar superposición preferida" - ) + MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, + "Explorar archivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, - "Superposiciones" - ) + MENU_ENUM_LABEL_VALUE_OPTIONAL, + "Opcional" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, - "Opacidad" - ) + MENU_ENUM_LABEL_VALUE_OVERLAY, + "Superposiciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, - "Superposición" - ) + MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, + "Auto-cargar superposición preferida" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, - "Escala" - ) + MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, + "Superposiciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, - "Superposición de pantalla" - ) + MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, + "Opacidad" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, - "Usar modo PAL60" - ) + MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, + "Superposición" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, - "Carpeta superior" - ) + MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, + "Escala" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, - "Pausar al activar el menú" - ) + MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, + "Superposición de pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE, - "Pausar al quedar en segundo plano" - ) + MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, + "Usar modo PAL60" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE, - "Contadores de rendimiento" - ) + MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, + "Carpeta superior" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB, - "Listas de reproducción" - ) + MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, + "Pausar al activar el menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, - "Listas de reproducción" - ) + MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE, + "Pausar al quedar en segundo plano" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, - "Listas de reproducción" - ) + MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE, + "Contadores de rendimiento" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, - "Soporte táctil" - ) + MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB, + "Listas de reproducción" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PORT, - "Puerto" - ) + MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, + "Listas de reproducción" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PRESENT, - "Presente" - ) + MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, + "Listas de reproducción" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS, - "Privacidad" - ) + MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, + "Soporte táctil" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIDI_SETTINGS, - "MIDI" - ) + MENU_ENUM_LABEL_VALUE_PORT, + "Puerto" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, - "Cerrar RetroArch" - ) + MENU_ENUM_LABEL_VALUE_PRESENT, + "Presente" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG, - "Soporte de analógico" - ) + MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS, + "Privacidad" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, - "BBFC Rating" - ) + MENU_ENUM_LABEL_VALUE_MIDI_SETTINGS, + "MIDI" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CERO_RATING, - "CERO Rating" - ) + MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, + "Cerrar RetroArch" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_COOP, - "Soporte de Co-op" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG, + "Soporte de analógico" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CRC32, - "CRC32" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, + "BBFC Rating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DESCRIPTION, - "Descripción" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CERO_RATING, + "CERO Rating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER, - "Desarrollador" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_COOP, + "Soporte de Co-op" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, - "Edición de la revista Edge" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CRC32, + "CRC32" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING, - "Calificación de la revista Edge" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DESCRIPTION, + "Descripción" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_REVIEW, - "Analisis de la revista Edge" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER, + "Desarrollador" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ELSPA_RATING, - "ELSPA Rating" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, + "Edición de la revista Edge" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, - "Enhancement Hardware" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING, + "Calificación de la revista Edge" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ESRB_RATING, - "ESRB Rating" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_REVIEW, + "Analisis de la revista Edge" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FAMITSU_MAGAZINE_RATING, - "Calificación de la revista Famitsu" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ELSPA_RATING, + "ELSPA Rating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE, - "Franquicia" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, + "Hardware de mejora" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GENRE, - "Género" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ESRB_RATING, + "ESRB Rating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MD5, - "MD5" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FAMITSU_MAGAZINE_RATING, + "Calificación de la revista Famitsu" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME, - "Nombre" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE, + "Franquicia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ORIGIN, - "Origen" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GENRE, + "Género" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PEGI_RATING, - "PEGI Rating" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MD5, + "MD5" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, - "Distribuidora" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME, + "Nombre" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, - "Mes de lanzamiento" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ORIGIN, + "Origen" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, - "Año de lanzamiento" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PEGI_RATING, + "PEGI Rating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RUMBLE, - "Soporte de vibración" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, + "Distribuidora" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SERIAL, - "Serial" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, + "Mes de lanzamiento" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1, - "SHA1" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, + "Año de lanzamiento" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, - "Ejecutar contenido" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RUMBLE, + "Soporte de vibración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, - "TGDB Rating" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SERIAL, + "Serial" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REBOOT, - "Reiniciar" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1, + "SHA1" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, - "Carpeta de configuración de grabación" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, + "Ejecutar contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, - "Carpeta de salida de grabación" - ) + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, + "TGDB Rating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS, - "Grabación" - ) + MENU_ENUM_LABEL_VALUE_REBOOT, + "Reiniciar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, - "Cargar configuración de grabación..." - ) + MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, + "Carpeta de configuración de grabación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, - "Controlador de grabación" - ) + MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, + "Carpeta de salida de grabación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIDI_DRIVER, - "Controlador MIDI" - ) + MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS, + "Grabación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, - "Activar grabación" - ) + MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, + "Cargar configuración de grabación..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RECORD_PATH, - "Guardar grabación como..." - ) + MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, + "Controlador de grabación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, - "Usar carpeta de salida" - ) + MENU_ENUM_LABEL_VALUE_MIDI_DRIVER, + "Controlador MIDI" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REMAP_FILE, - "Archivo de reasignación de controles" - ) + MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, + "Activar grabación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, - "Cargar archivo de reasignación" - ) + MENU_ENUM_LABEL_VALUE_RECORD_PATH, + "Guardar grabación como..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, - "Guardar controles para el núcleo" - ) + MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, + "Usar carpeta de salida" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CONTENT_DIR, - "Lugar donde guardar controles para el núcleo" - ) + MENU_ENUM_LABEL_VALUE_REMAP_FILE, + "Archivo de reasignación de controles" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, - "Guardar controles para el juego" - ) + MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, + "Cargar archivo de reasignación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE, - "Borrar controles personalizados del núcleo" - ) + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, + "Guardar controles para el núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME, - "Borrar controles personalizados del juego" - ) + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CONTENT_DIR, + "Lugar donde guardar controles para el núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CONTENT_DIR, - "Borrar directorio de controles personalizados" - ) + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, + "Guardar controles para el juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REQUIRED, - "Necesario" - ) + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE, + "Borrar controles personalizados del núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, - "Reiniciar" - ) + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME, + "Borrar controles personalizados del juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESTART_RETROARCH, - "Reiniciar RetroArch" - ) + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CONTENT_DIR, + "Borrar directorio de controles personalizados" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Reanudar" - ) + MENU_ENUM_LABEL_VALUE_REQUIRED, + "Necesario" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, - "Reanudar" - ) + MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, + "Reiniciar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, - "RetroKeyboard" - ) + MENU_ENUM_LABEL_VALUE_RESTART_RETROARCH, + "Reiniciar RetroArch" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RETROPAD, - "RetroPad" - ) + MENU_ENUM_LABEL_VALUE_RESUME, + "Reanudar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, - "RetroPad con Analógicos" - ) + MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, + "Reanudar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, - "Logros" - ) + MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, + "RetroKeyboard" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REWIND_ENABLE, - "Activar rebobinado" - ) + MENU_ENUM_LABEL_VALUE_RETROPAD, + "RetroPad" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REWIND_GRANULARITY, - "Nivel de detalle del rebobinado" - ) + MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, + "RetroPad con Analógicos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE, - "Tamaño del Búfer de rebobinado (MB)" - ) + MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, + "Logros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE_STEP, - "Tamaño del intervalo de ajuste del Búfer (MB)" - ) + MENU_ENUM_LABEL_VALUE_REWIND_ENABLE, + "Activar rebobinado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, - "Rebobinado" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_AFTER_TOGGLE, + "Aplicar después de cambiar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_DETAILS_SETTINGS, - "Detalles del truco" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_AFTER_LOAD, + "Auto-aplicar trucos durante la carga" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_SETTINGS, - "Iniciar o continuar búsqueda de trucos" - ) + MENU_ENUM_LABEL_VALUE_REWIND_GRANULARITY, + "Nivel de detalle del rebobinado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Explorador de archivos" - ) + MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE, + "Tamaño del Búfer de rebobinado (MB)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, - "Config" - ) + MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE_STEP, + "Tamaño del intervalo de ajuste del Búfer (MB)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, - "Mostrar pantalla de inicio" - ) + MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, + "Rebobinado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, - "Analógico derecho" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SETTINGS, + "Opciones de trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, - "Agregar a Favoritos" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_DETAILS_SETTINGS, + "Detalles del truco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES_PLAYLIST, - "Agregar a Favoritos" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_SETTINGS, + "Iniciar o continuar búsqueda de trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESET_CORE_ASSOCIATION, - "Restablecer asociación de núcleo" - ) + MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, + "Explorador de archivos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RUN, - "Iniciar" - ) + MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, + "Config" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RUN_MUSIC, - "Iniciar" - ) + MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, + "Mostrar pantalla de inicio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, - "Activar SAMBA" - ) + MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, + "Analógico derecho" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, - "Partidas guardadas" - ) + MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, + "Agregar a Favoritos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, - "Indizar automáticamente guardados rápidos" - ) + MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES_PLAYLIST, + "Agregar a Favoritos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, - "Cargar guardado rápido automáticamente" - ) + MENU_ENUM_LABEL_VALUE_RESET_CORE_ASSOCIATION, + "Restablecer asociación de núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, - "Guardado rápido automático" - ) + MENU_ENUM_LABEL_VALUE_RUN, + "Iniciar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, - "Guardados rápidos" - ) + MENU_ENUM_LABEL_VALUE_RUN_MUSIC, + "Iniciar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, - "Miniaturas de guardados rápidos" - ) + MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, + "Activar SAMBA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, - "Guardar configuración actual" - ) + MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, + "Partidas guardadas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, - "Guardar personalizaciones del núcleo" - ) + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, + "Indizar automáticamente guardados rápidos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, - "Lugar donde guardar personalizaciones del juego" - ) + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, + "Cargar guardado rápido automáticamente" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, - "Guardar personalizaciones del juego" - ) + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, + "Guardado rápido automático" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, - "Guardar configuración nueva" - ) + MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, + "Guardados rápidos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVE_STATE, - "Guardado rápido" - ) + MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, + "Miniaturas de guardados rápidos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, - "Guardado" - ) + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, + "Guardar configuración actual" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, - "Escanear carpeta" - ) + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Guardar personalizaciones del núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCAN_FILE, - "Escanear archivo" - ) + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, + "Lugar donde guardar personalizaciones del juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, - "" - ) + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, + "Guardar personalizaciones del juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, - "Capturas de pantalla" - ) + MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, + "Guardar configuración nueva" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, - "Resolución de pantalla" - ) + MENU_ENUM_LABEL_VALUE_SAVE_STATE, + "Guardado rápido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SEARCH, - "Buscar" - ) + MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, + "Guardado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SECONDS, - "segundos" - ) + MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, + "Escanear carpeta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SETTINGS, - "Ajustes" - ) + MENU_ENUM_LABEL_VALUE_SCAN_FILE, + "Escanear archivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, - "Ajustes" - ) + MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, + "" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHADER, - "Shader" - ) + MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, + "Capturas de pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, - "Aplicar cambios" - ) + MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, + "Resolución de pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS, - "Shaders" - ) + MENU_ENUM_LABEL_VALUE_SEARCH, + "Buscar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON, - "Ribbon" - ) + MENU_ENUM_LABEL_VALUE_SECONDS, + "segundos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON_SIMPLIFIED, - "Ribbon (simplificado)" - ) + MENU_ENUM_LABEL_VALUE_SETTINGS, + "Ajustes" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SIMPLE_SNOW, - "Nieve Simple" - ) + MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, + "Ajustes" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOW, - "Nieve" - ) + MENU_ENUM_LABEL_VALUE_SHADER, + "Shader" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, - "Mostrar ajustes avanzados" - ) + MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, + "Aplicar cambios" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, - "Mostrar archivos y carpetas ocultos" - ) + MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS, + "Shaders" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHUTDOWN, - "Apagar" - ) + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON, + "Ribbon" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, - "Velocidad de cámara lenta" - ) + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON_SIMPLIFIED, + "Ribbon (simplificado)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RUN_AHEAD_ENABLED, - "Reducir latencia usando Run-Ahead" - ) + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SIMPLE_SNOW, + "Nieve Simple" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RUN_AHEAD_FRAMES, - "Frames a ir por delante" - ) + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOW, + "Nieve" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RUN_AHEAD_SECONDARY_INSTANCE, - "Segunda instancia de RunAhead" - ) + MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, + "Mostrar ajustes avanzados" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RUN_AHEAD_HIDE_WARNINGS, - "Ocultar advertencias de RunAhead" - ) + MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, + "Mostrar archivos y carpetas ocultos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, - "Ordenar partidas guardadas por carpetas" - ) + MENU_ENUM_LABEL_VALUE_SHUTDOWN, + "Apagar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, - "Ordenar guardados rápidos por carpetas" - ) + MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, + "Velocidad de cámara lenta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE, - "Escribir guardado rápido en la carpeta del contenido" - ) + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_ENABLED, + "Reducir latencia usando Run-Ahead" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE, - "Escribir partida guardada en la carpeta del contenido" - ) + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_FRAMES, + "Frames a ir por delante" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, - "Archivos de Sistema están en la carpeta del contenido" - ) + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_SECONDARY_INSTANCE, + "Segunda instancia de RunAhead" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, - "Escribir capturas de pantalla en la carpeta del contenido" - ) + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_HIDE_WARNINGS, + "Ocultar advertencias de RunAhead" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SSH_ENABLE, - "Activar SSH" - ) + MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, + "Ordenar partidas guardadas por carpetas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_START_CORE, - "Iniciar núcleo" - ) + MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, + "Ordenar guardados rápidos por carpetas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD, - "Iniciar RetroPad remoto" - ) + MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE, + "Escribir guardado rápido en la carpeta del contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, - "Iniciar procesador de video" - ) + MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE, + "Escribir partida guardada en la carpeta del contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_STATE_SLOT, - "Posición de guardado" - ) + MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + "Archivos de Sistema están en la carpeta del contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_STATUS, - "Estado" - ) + MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + "Escribir capturas de pantalla en la carpeta del contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE, - "Comandos stdin" - ) + MENU_ENUM_LABEL_VALUE_SSH_ENABLE, + "Activar SSH" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SUPPORTED_CORES, - "Núcleos sugeridos" - ) + MENU_ENUM_LABEL_VALUE_START_CORE, + "Iniciar núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SUSPEND_SCREENSAVER_ENABLE, - "Suspender salvapantallas" - ) + MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD, + "Iniciar RetroPad remoto" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE, - "Activar música del sistema" - ) + MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, + "Iniciar procesador de video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, - "Sistema/BIOS" - ) + MENU_ENUM_LABEL_VALUE_STATE_SLOT, + "Posición de guardado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, - "Información del sistema" - ) + MENU_ENUM_LABEL_VALUE_STATUS, + "Estado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT, - "Soporte de 7zip" - ) + MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE, + "Comandos stdin" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT, - "Soporte de ALSA" - ) + MENU_ENUM_LABEL_VALUE_SUPPORTED_CORES, + "Núcleos sugeridos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_BUILD_DATE, - "Fecha de compilación" - ) + MENU_ENUM_LABEL_VALUE_SUSPEND_SCREENSAVER_ENABLE, + "Suspender salvapantallas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CG_SUPPORT, - "Soporte de Cg" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE, + "Activar música del sistema" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COCOA_SUPPORT, - "Soporte de Cocoa" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, + "Sistema/BIOS" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COMMAND_IFACE_SUPPORT, - "Soporte de interfaz de comandos" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, + "Información del sistema" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CORETEXT_SUPPORT, - "Soporte de CoreText" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT, + "Soporte de 7zip" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CPU_FEATURES, - "Características de CPU" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT, + "Soporte de ALSA" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_DPI, - "Mostrar DPI métricos" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_BUILD_DATE, + "Fecha de compilación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT, - "Mostrar alto métrico (mm)" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CG_SUPPORT, + "Soporte de Cg" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH, - "Mostrar ancho métrico (mm)" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COCOA_SUPPORT, + "Soporte de Cocoa" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DSOUND_SUPPORT, - "Soporte de DirectSound" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COMMAND_IFACE_SUPPORT, + "Soporte de interfaz de comandos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT, - "Soporte de WASAPI" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CORETEXT_SUPPORT, + "Soporte de CoreText" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, - "Soporte de librerías dinámicas" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CPU_FEATURES, + "Características de CPU" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, - "Carga dinámica en tiempo real de librería libretro" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_DPI, + "Mostrar DPI métricos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT, - "Soporte de EGL" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT, + "Mostrar alto métrico (mm)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT, - "Soporte de render-to-texture OpenGL/Direct3D (shaders multipasos)" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH, + "Mostrar ancho métrico (mm)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FFMPEG_SUPPORT, - "Soporte de FFmpeg" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DSOUND_SUPPORT, + "Soporte de DirectSound" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FREETYPE_SUPPORT, - "Soporte de FreeType" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT, + "Soporte de WASAPI" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER, - "Identificador del frontend" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, + "Soporte de librerías dinámicas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_NAME, - "Nombre del frontend" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, + "Carga dinámica en tiempo real de librería libretro" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_OS, - "S.O. del frontend" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT, + "Soporte de EGL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GIT_VERSION, - "Versión de Git" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT, + "Soporte de render-to-texture OpenGL/Direct3D (shaders multipasos)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GLSL_SUPPORT, - "Soporte de GLSL" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FFMPEG_SUPPORT, + "Soporte de FFmpeg" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_HLSL_SUPPORT, - "Soporte de HLSL" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FREETYPE_SUPPORT, + "Soporte de FreeType" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_JACK_SUPPORT, - "Soporte de JACK" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER, + "Identificador del frontend" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_KMS_SUPPORT, - "Soporte de KMS/EGL" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_NAME, + "Nombre del frontend" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LAKKA_VERSION, - "Versión de Lakka" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_OS, + "S.O. del frontend" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBRETRODB_SUPPORT, - "Soporte de LibretroDB" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GIT_VERSION, + "Versión de Git" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, - "Soporte de Libusb" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GLSL_SUPPORT, + "Soporte de GLSL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBXML2_SUPPORT, - "Soporte de parseo XML libxml2" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_HLSL_SUPPORT, + "Soporte de HLSL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, - "Soporte de juego en red (peer-to-peer)" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_JACK_SUPPORT, + "Soporte de JACK" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, - "Soporte de interfaz de comandos en red" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_KMS_SUPPORT, + "Soporte de KMS/EGL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_REMOTE_SUPPORT, - "Soporte de mando en red" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LAKKA_VERSION, + "Versión de Lakka" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT, - "Soporte de OpenAL" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBRETRODB_SUPPORT, + "Soporte de LibretroDB" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT, - "Soporte de OpenGL ES" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, + "Soporte de Libusb" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGL_SUPPORT, - "Soporte de OpenGL" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBXML2_SUPPORT, + "Soporte de parseo XML libxml2" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENSL_SUPPORT, - "Soporte de OpenSL" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, + "Soporte de juego en red (peer-to-peer)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENVG_SUPPORT, - "Soporte de OpenVG" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, + "Soporte de interfaz de comandos en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OSS_SUPPORT, - "Soporte de OSS" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_REMOTE_SUPPORT, + "Soporte de mando en red" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OVERLAY_SUPPORT, - "Soporte de superposiciones" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT, + "Soporte de OpenAL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE, - "Fuente de alimentación" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT, + "Soporte de OpenGL ES" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGED, - "Cargada" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGL_SUPPORT, + "Soporte de OpenGL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGING, - "Cargando" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENSL_SUPPORT, + "Soporte de OpenSL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_DISCHARGING, - "Descargando" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENVG_SUPPORT, + "Soporte de OpenVG" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE, - "No hay una fuente" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OSS_SUPPORT, + "Soporte de OSS" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, - "Soporte de PulseAudio" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OVERLAY_SUPPORT, + "Soporte de superposiciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PYTHON_SUPPORT, - "Soporte de Python (soporte de scripts para shaders)" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE, + "Fuente de alimentación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RBMP_SUPPORT, - "Soporte de BMP (RBMP)" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGED, + "Cargada" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RETRORATING_LEVEL, - "Nivel de RetroRating" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGING, + "Cargando" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RJPEG_SUPPORT, - "Soporte de JPEG (RJPEG)" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_DISCHARGING, + "Descargando" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ROARAUDIO_SUPPORT, - "Soporte de RoarAudio" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE, + "No hay una fuente" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RPNG_SUPPORT, - "Soporte de PNG (RPNG)" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, + "Soporte de PulseAudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RSOUND_SUPPORT, - "Soporte de RSound" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PYTHON_SUPPORT, + "Soporte de Python (soporte de scripts para shaders)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RTGA_SUPPORT, - "Soporte de TGA (RTGA)" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RBMP_SUPPORT, + "Soporte de BMP (RBMP)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, - "Soporte de SDL2" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RETRORATING_LEVEL, + "Nivel de RetroRating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_IMAGE_SUPPORT, - "Soporte de imágenes SDL" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RJPEG_SUPPORT, + "Soporte de JPEG (RJPEG)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_SUPPORT, - "Soporte de SDL1.2" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ROARAUDIO_SUPPORT, + "Soporte de RoarAudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SLANG_SUPPORT, - "Soporte de Slang" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RPNG_SUPPORT, + "Soporte de PNG (RPNG)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_THREADING_SUPPORT, - "Soporte de hilos" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RSOUND_SUPPORT, + "Soporte de RSound" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, - "Soporte de Udev" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RTGA_SUPPORT, + "Soporte de TGA (RTGA)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, - "Soporte de Video4Linux2" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, + "Soporte de SDL2" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER, - "Controlador de contexto de video" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_IMAGE_SUPPORT, + "Soporte de imágenes SDL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, - "Soporte de Vulkan" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_SUPPORT, + "Soporte de SDL1.2" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_METAL_SUPPORT, - "Soporte de Metal" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SLANG_SUPPORT, + "Soporte de Slang" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT, - "Soporte de Wayland" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_THREADING_SUPPORT, + "Soporte de hilos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_X11_SUPPORT, - "Soporte de X11" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, + "Soporte de Udev" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XAUDIO2_SUPPORT, - "Soporte de XAudio2" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, + "Soporte de Video4Linux2" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT, - "Soporte de XVideo" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER, + "Controlador de contexto de video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT, - "Soporte de Zlib" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, + "Soporte de Vulkan" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, - "Capturar pantalla" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_METAL_SUPPORT, + "Soporte de Metal" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, - "Tareas en hilos" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT, + "Soporte de Wayland" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_THUMBNAILS, - "Miniaturas" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_X11_SUPPORT, + "Soporte de X11" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS, - "Miniaturas Izquierdas" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XAUDIO2_SUPPORT, + "Soporte de XAudio2" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_VERTICAL_THUMBNAILS, - "Miniaturas Disposición Vertical" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT, + "Soporte de XVideo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, - "Miniaturas" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT, + "Soporte de Zlib" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, - "Actualizador de miniaturas" - ) + MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, + "Capturar pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, - "Cajas" - ) + MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, + "Tareas en hilos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, - "Capturas de pantalla" - ) + MENU_ENUM_LABEL_VALUE_THUMBNAILS, + "Miniaturas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, - "Pantallas de título" - ) + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS, + "Miniaturas Izquierdas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, - "Mostrar fecha y hora" - ) + MENU_ENUM_LABEL_VALUE_XMB_VERTICAL_THUMBNAILS, + "Miniaturas Disposición Vertical" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_TITLE_COLOR, - "Color de títulos del menú" - ) + MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, + "Miniaturas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_TRUE, - "Activado" - ) + MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, + "Actualizador de miniaturas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, - "Activar IU ayudante" - ) + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, + "Cajas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, - "Ejecutar al inicio la IU ayudante" - ) + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, + "Capturas de pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UI_COMPANION_TOGGLE, - "Mostrar menú de escritorio al inicio" - ) + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, + "Pantallas de título" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DESKTOP_MENU_ENABLE, - "Activar menú de escritorio (reiniciar)" - ) + MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, + "Mostrar fecha y hora" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, - "Barra de menús" - ) + MENU_ENUM_LABEL_VALUE_TITLE_COLOR, + "Color de títulos del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE, - "No se ha podido leer el archivo comprimido" - ) + MENU_ENUM_LABEL_VALUE_TRUE, + "Activado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, - "Deshacer carga" - ) + MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, + "Activar IU ayudante" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, - "Deshacer guardado" - ) + MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, + "Ejecutar al inicio la IU ayudante" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UNKNOWN, - "Desconocido" - ) + MENU_ENUM_LABEL_VALUE_UI_COMPANION_TOGGLE, + "Mostrar menú de escritorio al inicio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, - "Actualizador" - ) + MENU_ENUM_LABEL_VALUE_DESKTOP_MENU_ENABLE, + "Activar menú de escritorio (reiniciar)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, - "Actualizar recursos" - ) + MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, + "Barra de menús" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "Actualizar perfiles de auto-configuración" - ) + MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE, + "No se ha podido leer el archivo comprimido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, - "Actualizar shaders Cg" - ) + MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, + "Deshacer carga" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, - "Actualizar trucos" - ) + MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, + "Deshacer guardado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, - "Actualizar archivos de info de núcleo" - ) + MENU_ENUM_LABEL_VALUE_UNKNOWN, + "Desconocido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, - "Actualizar bases de datos" - ) + MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, + "Actualizador" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, - "Actualizar shaders GLSL" - ) + MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, + "Actualizar recursos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, - "Actualizar Lakka" - ) + MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, + "Actualizar perfiles de auto-configuración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, - "Actualizar superposiciones" - ) + MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, + "Actualizar shaders Cg" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_UPDATE_SLANG_SHADERS, - "Actualizar shaders Slang" - ) + MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, + "Actualizar trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USER, - "Usuario" - ) + MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, + "Actualizar archivos de info de núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_KEYBOARD, - "Teclado" - ) + MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, + "Actualizar bases de datos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS, - "Interfaz de usuario" - ) + MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, + "Actualizar shaders GLSL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USER_LANGUAGE, - "Idioma" - ) + MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, + "Actualizar Lakka" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USER_SETTINGS, - "Usuario" - ) + MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, + "Actualizar superposiciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Usar visor de imágenes integrado" - ) + MENU_ENUM_LABEL_VALUE_UPDATE_SLANG_SHADERS, + "Actualizar shaders Slang" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Usar visor de medios integrado" - ) + MENU_ENUM_LABEL_VALUE_USER, + "Usuario" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, - "" - ) + MENU_ENUM_LABEL_VALUE_KEYBOARD, + "Teclado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, - "Permitir rotación" - ) + MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS, + "Interfaz de usuario" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO, - "Configurar relación de aspecto" - ) + MENU_ENUM_LABEL_VALUE_USER_LANGUAGE, + "Idioma" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, - "Relación de aspecto automática" - ) + MENU_ENUM_LABEL_VALUE_USER_SETTINGS, + "Usuario" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, - "Relación de aspecto" - ) + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Usar visor de imágenes integrado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, - "Insertar frames negros" - ) + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Usar visor de medios integrado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, - "Recortar Overscan (Reinicio)" - ) + MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, + "" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, - "Desactivar composición de escritorio" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, + "Permitir rotación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER, - "Controlador de video" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO, + "Configurar relación de aspecto" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FILTER, - "Filtro de video" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, + "Relación de aspecto automática" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, - "Filtro de video" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, + "Relación de aspecto" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, - "Filtro de parpadeo" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, + "Insertar frames negros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, - "Mostrar notificaciones en pantalla" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, + "Recortar Overscan (Reinicio)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, - "Fuente de notificación" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, + "Desactivar composición de escritorio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, - "Tamaño de notificación" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER, + "Controlador de video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, - "Forzar relación de aspecto" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER, + "Filtro de video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE, - "Forzar desactivación del FBO sRGB" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, + "Filtro de video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, - "Retraso de frames" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, + "Filtro de parpadeo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, - "Iniciar en pantalla completa" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, + "Mostrar notificaciones en pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, - "Gamma de video" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, + "Fuente de notificación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, - "Activar grabación de GPU" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, + "Tamaño de notificación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, - "Permitir capturas de pantalla de GPU" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, + "Forzar relación de aspecto" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC, - "Sincronía estricta de GPU" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE, + "Forzar desactivación del FBO sRGB" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC_FRAMES, - "Frames para sincronía estricta" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, + "Retraso de frames" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, - "Máximo de imágenes en swapchain" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, + "Iniciar en pantalla completa" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, - "Posición X de notificaciones" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, + "Gamma de video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, - "Posición Y de notificaciones" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, + "Activar grabación de GPU" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, - "Índice del monitor" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, + "Permitir capturas de pantalla de GPU" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, - "Activar grabación con filtros" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC, + "Sincronía estricta de GPU" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, - "Frecuencia de actualización" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC_FRAMES, + "Frames para sincronía estricta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, - "Frecuencia estimada del monitor" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Máximo de imágenes en swapchain" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_POLLED, - "Set Display-Reported Refresh Rate" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, + "Posición X de notificaciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_ROTATION, - "Rotación" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, + "Posición Y de notificaciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SCALE, - "Escala en ventana" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, + "Índice del monitor" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, - "Escalar usando enteros" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, + "Activar grabación con filtros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, - "Video" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, + "Frecuencia de actualización" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, - "Shader de video" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, + "Frecuencia estimada del monitor" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, - "Pasadas del shader" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_POLLED, + "Set Display-Reported Refresh Rate" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, - "Previsualizar parámetros de shaders" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_ROTATION, + "Rotación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, - "Cargar preset de shaders" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE, + "Escala en ventana" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, - "Guardar preset de shaders como..." - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, + "Escalar usando enteros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, - "Guardar preset para el núcleo" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, + "Video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT, - "Guardar preset de directorio de contenido" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, + "Shader de video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, - "Guardar preset para el juego" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, + "Pasadas del shader" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, - "Activar contexto compartido por HW" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, + "Previsualizar parámetros de shaders" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, - "Filtrado bilineal" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, + "Cargar preset de shaders" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, - "Activar filtros por software" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, + "Guardar preset de shaders como..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, - "Intervalo de intercambio de Vsync" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, + "Guardar preset para el núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_TAB, - "Video" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT, + "Guardar preset de directorio de contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, - "Video por hilos" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, + "Guardar preset para el juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, - "Filtro contra parpadeos" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, + "Activar contexto compartido por HW" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "Altura de relación de aspecto personalizada" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, + "Filtrado bilineal" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "Ancho de relación de aspecto personalizada" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, + "Activar filtros por software" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, - "Custom Aspect Ratio X Pos" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, + "Intervalo de intercambio de Vsync" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, - "Custom Aspect Ratio Y Pos" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_TAB, + "Video" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, - "Asignar ancho de interfaz visual" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, + "Video por hilos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, - "Sincronía vertical (VSync)" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, + "Filtro contra parpadeos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, - "Pantalla completa en ventana" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, + "Altura de relación de aspecto personalizada" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, - "Ancho de la ventana" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, + "Ancho de relación de aspecto personalizada" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, - "Alto de la ventana" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, + "Custom Aspect Ratio X Pos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_X, - "Ancho en pantalla completa" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, + "Custom Aspect Ratio Y Pos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_Y, - "Alto en pantalla completa" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, + "Asignar ancho de interfaz visual" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, - "Controlador Wi-Fi" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, + "Sincronía vertical (VSync)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, - "Wi-Fi" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, + "Pantalla completa en ventana" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, - "Transparencia del menú" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, + "Ancho de la ventana" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_RED, - "Fuente del Menú componente roja" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, + "Alto de la ventana" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_GREEN, - "Fuente del Menú componente verde" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_X, + "Ancho en pantalla completa" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_BLUE, - "Fuente del Menú componente azul" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_Y, + "Alto en pantalla completa" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_FONT, - "Fuente del menú" - ) + MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, + "Controlador Wi-Fi" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, - "Personalizado" - ) + MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, + "Wi-Fi" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, - "FlatUI" - ) + MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, + "Transparencia del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME, - "Monochrome" - ) + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_RED, + "Fuente del Menú componente roja" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME_INVERTED, - "Monochrome Invertido" - ) + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_GREEN, + "Fuente del Menú componente verde" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_SYSTEMATIC, - "Systematic" - ) + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_BLUE, + "Fuente del Menú componente azul" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_NEOACTIVE, - "NeoActive" - ) + MENU_ENUM_LABEL_VALUE_XMB_FONT, + "Fuente del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_PIXEL, - "Pixel" - ) + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, + "Personalizado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, - "RetroActive" - ) + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, + "FlatUI" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROSYSTEM, - "Retrosystem" - ) + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME, + "Monochrome" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, - "Dot-Art" - ) + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME_INVERTED, + "Monochrome Invertido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, - "Color del menú" - ) + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_SYSTEMATIC, + "Systematic" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_APPLE_GREEN, - "Verde manzana" - ) + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_NEOACTIVE, + "NeoActive" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK, - "Oscuro" - ) + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_PIXEL, + "Pixel" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LIGHT, - "Claro" - ) + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, + "RetroActive" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MORNING_BLUE, - "Azul Mañana" - ) + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROSYSTEM, + "Retrosystem" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK_PURPLE, - "Violeta" - ) + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, + "Dot-Art" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ELECTRIC_BLUE, - "Azul Eléctrico" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, + "Color del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GOLDEN, - "Dorado" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_APPLE_GREEN, + "Verde manzana" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LEGACY_RED, - "Rojo" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK, + "Oscuro" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDNIGHT_BLUE, - "Azul Medianoche" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LIGHT, + "Claro" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_PLAIN, - "Nada" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MORNING_BLUE, + "Azul Mañana" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, - "Bajo el mar" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK_PURPLE, + "Violeta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, - "Rojo Volcánico" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ELECTRIC_BLUE, + "Azul Eléctrico" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, - "Menú Shader Pipeline" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GOLDEN, + "Dorado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, - "Escala del menú" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LEGACY_RED, + "Rojo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, - "Sombras de iconos" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDNIGHT_BLUE, + "Azul Medianoche" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_HISTORY, - "Mostrar pestaña historial" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_PLAIN, + "Nada" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, - "Mostrar pestaña importar contenido" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, + "Bajo el mar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, - "Mostrar pestañas de Playlists" - ) + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, + "Rojo Volcánico" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_FAVORITES, - "Mostrar pestaña favoritos" - ) + MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, + "Menú Shader Pipeline" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_IMAGES, - "Mostrar pestaña imágenes" - ) + MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, + "Escala del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_MUSIC, - "Mostrar pestaña música" - ) + MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, + "Sombras de iconos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS, - "Mostrar pestaña configuración" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_HISTORY, + "Mostrar pestaña historial" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO, - "Mostrar pestaña video" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, + "Mostrar pestaña importar contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, - "Mostrar pestaña juego en red" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, + "Mostrar pestañas de Playlists" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_LAYOUT, - "Disposición del menú" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_FAVORITES, + "Mostrar pestaña favoritos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_THEME, - "Tema de iconos del menú" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_IMAGES, + "Mostrar pestaña imágenes" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_YES, - "Sí" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_MUSIC, + "Mostrar pestaña música" + ) MSG_HASH( - MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, - "Preset de shader" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS, + "Mostrar pestaña configuración" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, - "Activar logros. Para más información, visita http://retroachievements.org" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO, + "Mostrar pestaña video" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, - "Activar logros no oficiales y/o beta para probarlos" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, + "Mostrar pestaña juego en red" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, - "Duplica puntos pero desactiva guardado rápido, trucos, rebobinar, y cámara lenta para todos los juegos" - ) + MENU_ENUM_LABEL_VALUE_XMB_LAYOUT, + "Disposición del menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEEVOS_LEADERBOARDS_ENABLE, - "No tiene efecto si el modo hardcore está desactivado" - ) + MENU_ENUM_LABEL_VALUE_XMB_THEME, + "Tema de iconos del menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEEVOS_BADGES_ENABLE, - "Activar para ver miniaturas en la lista de logros" - ) + MENU_ENUM_LABEL_VALUE_YES, + "Sí" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE, - "Activar para ver notificaciones mas informativas sobre logros" - ) + MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, + "Preset de shader" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEEVOS_AUTO_SCREENSHOT, - "Automaticamente hacer una captura de pantalla al obtener un logro" - ) + MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, + "Activar logros. Para más información, visita http://retroachievements.org" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, - "Cambia los controladores usados por el sistema" - ) + MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, + "Activar logros no oficiales y/o beta para probarlos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "Opciones de los logros" - ) + MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, + "Duplica puntos pero desactiva guardado rápido, trucos, rebobinar, y cámara lenta para todos los juegos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_SETTINGS, - "Opciones de los núcleos" - ) + MENU_ENUM_SUBLABEL_CHEEVOS_LEADERBOARDS_ENABLE, + "No tiene efecto si el modo hardcore está desactivado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, - "Opciones de grabación" - ) + MENU_ENUM_SUBLABEL_CHEEVOS_BADGES_ENABLE, + "Activar para ver miniaturas en la lista de logros" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, - "Opciones de notificaciones, controles en pantalla y marcos" - ) + MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE, + "Activar para ver notificaciones mas informativas sobre logros" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, - "Opciones de rebobinado, adelantado y cámara lenta" - ) + MENU_ENUM_SUBLABEL_CHEEVOS_AUTO_SCREENSHOT, + "Automaticamente hacer una captura de pantalla al obtener un logro" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVING_SETTINGS, - "Opciones de guardado" - ) + MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, + "Cambia los controladores usados por el sistema" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, - "Opciones de registro" - ) + MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, + "Opciones de los logros" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, - "Opciones de la interfaz de usuario" - ) + MENU_ENUM_SUBLABEL_CORE_SETTINGS, + "Opciones de los núcleos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_USER_SETTINGS, - "Opciones de cuentas, nombre de usuario y lenguaje" - ) + MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, + "Opciones de grabación" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, - "Opciones de privacidad" - ) + MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, + "Opciones de notificaciones, controles en pantalla y marcos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIDI_SETTINGS, - "Cambiar opciones MIDI" - ) + MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, + "Opciones de rebobinado, adelantado y cámara lenta" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, - "Cambia las carpetas por defecto donde se encuentran los archivos" - ) + MENU_ENUM_SUBLABEL_SAVING_SETTINGS, + "Opciones de guardado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, - "Opciones de las listas de juegos" - ) + MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, + "Opciones de registro" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, - "Opciones de servidor y red" - ) + MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, + "Opciones de la interfaz de usuario" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, - "Escanear contenido y agregar a la base de datos" - ) + MENU_ENUM_SUBLABEL_USER_SETTINGS, + "Opciones de cuentas, nombre de usuario y lenguaje" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, - "Opciones de salida de audio" - ) + MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, + "Opciones de privacidad" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, - "Activar o desactivar Bluetooth" - ) + MENU_ENUM_SUBLABEL_MIDI_SETTINGS, + "Cambiar opciones MIDI" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, - "Guarda los cambios en el archivo de configuración al salir" - ) + MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, + "Cambia las carpetas por defecto donde se encuentran los archivos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, - "Opciones de los archivos de configuración" - ) + MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, + "Opciones de las listas de juegos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, - "Administrar y crear archivos de configuración" - ) + MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, + "Opciones de servidor y red" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CPU_CORES, - "Cantidad de núcleos que tiene la CPU" - ) + MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, + "Escanear contenido y agregar a la base de datos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_FPS_SHOW, - "Muestra la velocidad de cuadros por segundo" - ) + MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, + "Opciones de salida de audio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, - "Opciones de teclas rápidas (hotkeys)" - ) + MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, + "Activar o desactivar Bluetooth" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Combinación de botones del mando para mostrar el menú" - ) + MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, + "Guarda los cambios en el archivo de configuración al salir" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_SETTINGS, - "Opciones de mando, teclado y ratón" - ) + MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, + "Opciones de los archivos de configuración" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, - "Cambiar los controles para este usuario" - ) + MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, + "Administrar y crear archivos de configuración" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LATENCY_SETTINGS, - "Ajustar la latencia por medio de opciones relacionadas con el video, audio y entradas" - ) + MENU_ENUM_SUBLABEL_CPU_CORES, + "Cantidad de núcleos que tiene la CPU" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LOG_VERBOSITY, - "Activar o desactivar registros a la terminal" - ) + MENU_ENUM_SUBLABEL_FPS_SHOW, + "Muestra la velocidad de cuadros por segundo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY, - "Unirse o ser servidor de una sesión de juego en red" - ) + MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, + "Opciones de teclas rápidas (hotkeys)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, - "Buscar y conectarse a anfitriones de juego en red en la red local" - ) + MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, + "Combinación de botones del mando para mostrar el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Muestra la información de sistema" - ) + MENU_ENUM_SUBLABEL_INPUT_SETTINGS, + "Opciones de mando, teclado y ratón" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ONLINE_UPDATER, - "Descarga componentes y contenido adicional para RetroArch" - ) + MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, + "Cambiar los controles para este usuario" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAMBA_ENABLE, - "Activar o desactivar el compartido de carpetas en red" - ) + MENU_ENUM_SUBLABEL_LATENCY_SETTINGS, + "Ajustar la latencia por medio de opciones relacionadas con el video, audio y entradas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, - "Administrar los servicios del sistema operativo" - ) + MENU_ENUM_SUBLABEL_LOG_VERBOSITY, + "Activar o desactivar registros a la terminal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, - "Mostrar archivos y carpetas ocultos en el explorador de archivos" - ) + MENU_ENUM_SUBLABEL_NETPLAY, + "Unirse o ser servidor de una sesión de juego en red" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SSH_ENABLE, - "Activar o desactivar acceso remoto por linea de comandos" - ) + MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, + "Buscar y conectarse a anfitriones de juego en red en la red local" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, - "Evita que el protector de pantalla se active" - ) + MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, + "Muestra la información de sistema" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, - "Hacer que el tamaño de la ventana sea relativo al núcleo. Alternativamente, puedes fijar el tamaño mas abajo" - ) + MENU_ENUM_SUBLABEL_ONLINE_UPDATER, + "Descarga componentes y contenido adicional para RetroArch" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_USER_LANGUAGE, - "Cambia el lenguaje de la interfaz" - ) + MENU_ENUM_SUBLABEL_SAMBA_ENABLE, + "Activar o desactivar el compartido de carpetas en red" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Insertar un cuadro negro intermedio, Útil para usuarios con pantallas de 120hz que quieren eliminar ghosting en el contenido de 60hz" - ) + MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, + "Administrar los servicios del sistema operativo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, - "Reducir latencia a costa de un mayor riesgo de tirones. Agrega un retraso después del VSync en milisegundos" - ) + MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, + "Mostrar archivos y carpetas ocultos en el explorador de archivos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, - "Cuantos cuadros puede ir la CPU por delante de la GPU al usar 'Sincronía estricta de GPU'" - ) + MENU_ENUM_SUBLABEL_SSH_ENABLE, + "Activar o desactivar acceso remoto por linea de comandos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, - "Informa al controlador que use el modo de buffering especificado (doble, triple, etc.)" - ) + MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, + "Evita que el protector de pantalla se active" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, - "Seleccionar la pantalla a usar" - ) + MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, + "Hacer que el tamaño de la ventana sea relativo al núcleo. Alternativamente, puedes fijar el tamaño mas abajo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, - "Estimado preciso de refresco de la pantalla en Hz" - ) + MENU_ENUM_SUBLABEL_USER_LANGUAGE, + "Cambia el lenguaje de la interfaz" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_POLLED, - "La tasa de refresco indicada por el controlador de pantalla" - ) + MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, + "Insertar un cuadro negro intermedio, Útil para usuarios con pantallas de 120hz que quieren eliminar ghosting en el contenido de 60hz" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, - "Opciones de salida de video" - ) + MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, + "Reducir latencia a costa de un mayor riesgo de tirones. Agrega un retraso después del VSync en milisegundos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_WIFI_SETTINGS, - "Escanear redes inalambricas y conectarse" - ) + MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, + "Cuantos cuadros puede ir la CPU por delante de la GPU al usar 'Sincronía estricta de GPU'" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_HELP_LIST, - "Aprender como funciona el programa" - ) + MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Informa al controlador que use el modo de buffering especificado (doble, triple, etc.)" + ) MSG_HASH( - MSG_ADDED_TO_FAVORITES, - "Agregado a los favoritos" - ) + MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, + "Seleccionar la pantalla a usar" + ) MSG_HASH( - MSG_RESET_CORE_ASSOCIATION, - "Restablecida la asociación de la entrada de la lista" - ) + MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, + "Estimado preciso de refresco de la pantalla en Hz" + ) MSG_HASH( - MSG_APPENDED_DISK, - "Disco encolado" - ) + MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_POLLED, + "La tasa de refresco indicada por el controlador de pantalla" + ) MSG_HASH( - MSG_APPLICATION_DIR, - "Carpeta de la aplicación" - ) + MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, + "Opciones de salida de video" + ) MSG_HASH( - MSG_APPLYING_CHEAT, - "Aplicando trucos" - ) + MENU_ENUM_SUBLABEL_WIFI_SETTINGS, + "Escanear redes inalambricas y conectarse" + ) MSG_HASH( - MSG_APPLYING_SHADER, - "Aplicando shader" - ) + MENU_ENUM_SUBLABEL_HELP_LIST, + "Aprender como funciona el programa" + ) MSG_HASH( - MSG_AUDIO_MUTED, - "Silencio" - ) + MSG_ADDED_TO_FAVORITES, + "Agregado a los favoritos" + ) MSG_HASH( - MSG_AUDIO_UNMUTED, - "Audio normal" - ) + MSG_RESET_CORE_ASSOCIATION, + "Restablecida la asociación de la entrada de la lista" + ) MSG_HASH( - MSG_AUTOCONFIG_FILE_ERROR_SAVING, - "Error guardando archivo de auto-configuración" - ) + MSG_APPENDED_DISK, + "Disco encolado" + ) MSG_HASH( - MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, - "Archivo de auto-configuración guardado exitosamente" - ) + MSG_APPLICATION_DIR, + "Carpeta de la aplicación" + ) MSG_HASH( - MSG_AUTOSAVE_FAILED, - "No se puede inicializar autogurardado" - ) + MSG_APPLYING_CHEAT, + "Aplicando trucos" + ) MSG_HASH( - MSG_AUTO_SAVE_STATE_TO, - "Auto guardar en" - ) + MSG_APPLYING_SHADER, + "Aplicando shader" + ) MSG_HASH( - MSG_BLOCKING_SRAM_OVERWRITE, - "Bloquear sobrescritura de SaveRAM" - ) + MSG_AUDIO_MUTED, + "Silencio" + ) MSG_HASH( - MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, - "Iniciando la linea de comandos en el puerto" - ) + MSG_AUDIO_UNMUTED, + "Audio normal" + ) MSG_HASH( - MSG_BYTES, - "bytes" - ) + MSG_AUTOCONFIG_FILE_ERROR_SAVING, + "Error guardando archivo de auto-configuración" + ) MSG_HASH( - MSG_CANNOT_INFER_NEW_CONFIG_PATH, - "No se puede inferir la nueva ruta de configuración. Use el tiempo actual" - ) + MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, + "Archivo de auto-configuración guardado exitosamente" + ) MSG_HASH( - MSG_CHEEVOS_HARDCORE_MODE_ENABLE, - "Modo hardcore activado, guardado rápido y rebobinado deshabilitados" - ) + MSG_AUTOSAVE_FAILED, + "No se puede inicializar autogurardado" + ) MSG_HASH( - MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, - "Comparando con números mágicos conocidos..." - ) + MSG_AUTO_SAVE_STATE_TO, + "Auto guardar en" + ) MSG_HASH( - MSG_COMPILED_AGAINST_API, - "Compilado para la API" - ) + MSG_BLOCKING_SRAM_OVERWRITE, + "Bloquear sobrescritura de SaveRAM" + ) MSG_HASH( - MSG_CONFIG_DIRECTORY_NOT_SET, - "Carpeta de configuración no establecida. No se puede guardar la configuración" - ) + MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, + "Iniciando la linea de comandos en el puerto" + ) MSG_HASH( - MSG_CONNECTED_TO, - "Conectado a" - ) + MSG_BYTES, + "bytes" + ) MSG_HASH( - MSG_CONTENT_CRC32S_DIFFER, - "No se pueden usar diferentes juegos. (El CRC32s difiere)" - ) + MSG_CANNOT_INFER_NEW_CONFIG_PATH, + "No se puede inferir la nueva ruta de configuración. Use el tiempo actual" + ) MSG_HASH( - MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, - "Carga de contenido saltada. La implementación usara la suya" - ) + MSG_CHEEVOS_HARDCORE_MODE_ENABLE, + "Modo hardcore activado, guardado rápido y rebobinado deshabilitados" + ) MSG_HASH( - MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "El núcleo no soporta guardados rápidos" - ) + MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, + "Comparando con números mágicos conocidos..." + ) MSG_HASH( - MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, - "Archivo de opciones del núcleo creado exitosamente" - ) + MSG_COMPILED_AGAINST_API, + "Compilado para la API" + ) MSG_HASH( - MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, - "No se encuentra otro controlador" - ) + MSG_CONFIG_DIRECTORY_NOT_SET, + "Carpeta de configuración no establecida. No se puede guardar la configuración" + ) MSG_HASH( - MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, - "No se encuentra un sistema compatible" - ) + MSG_CONNECTED_TO, + "Conectado a" + ) MSG_HASH( - MSG_COULD_NOT_FIND_VALID_DATA_TRACK, - "No se encuentra una pista de datos válido" - ) + MSG_CONTENT_CRC32S_DIFFER, + "No se pueden usar diferentes juegos. (El CRC32s difiere)" + ) MSG_HASH( - MSG_COULD_NOT_OPEN_DATA_TRACK, - "No se puede abrir la pista de datos" - ) + MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, + "Carga de contenido saltada. La implementación usara la suya" + ) MSG_HASH( - MSG_COULD_NOT_READ_CONTENT_FILE, - "No se puede leer el contenido" - ) + MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, + "El núcleo no soporta guardados rápidos" + ) MSG_HASH( - MSG_COULD_NOT_READ_MOVIE_HEADER, - "No se puede leer el encabezado de la película" - ) + MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, + "Archivo de opciones del núcleo creado exitosamente" + ) MSG_HASH( - MSG_COULD_NOT_READ_STATE_FROM_MOVIE, - "No se puede leer el estado del película" - ) + MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, + "No se encuentra otro controlador" + ) MSG_HASH( - MSG_CRC32_CHECKSUM_MISMATCH, - "El CRC32 del contenido no concuerda con el del replay, Es probable que se de-sincronice al reproducir" - ) + MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, + "No se encuentra un sistema compatible" + ) MSG_HASH( - MSG_CUSTOM_TIMING_GIVEN, - "Timing personalizado provisto" - ) + MSG_COULD_NOT_FIND_VALID_DATA_TRACK, + "No se encuentra una pista de datos válido" + ) MSG_HASH( - MSG_DECOMPRESSION_ALREADY_IN_PROGRESS, - "Descompresión en progreso" - ) + MSG_COULD_NOT_OPEN_DATA_TRACK, + "No se puede abrir la pista de datos" + ) MSG_HASH( - MSG_DECOMPRESSION_FAILED, - "Fallo al descomprimir" - ) + MSG_COULD_NOT_READ_CONTENT_FILE, + "No se puede leer el contenido" + ) MSG_HASH( - MSG_DETECTED_VIEWPORT_OF, - "Detectado viewport de" - ) + MSG_COULD_NOT_READ_MOVIE_HEADER, + "No se puede leer el encabezado de la película" + ) MSG_HASH( - MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, - "No se encontró un parche válido" - ) + MSG_COULD_NOT_READ_STATE_FROM_MOVIE, + "No se puede leer el estado del película" + ) MSG_HASH( - MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, - "Desconecte el dispositivo desde un puerto válido" - ) + MSG_CRC32_CHECKSUM_MISMATCH, + "El CRC32 del contenido no concuerda con el del replay, Es probable que se de-sincronice al reproducir" + ) MSG_HASH( - MSG_DISK_CLOSED, - "Cerrado" - ) + MSG_CUSTOM_TIMING_GIVEN, + "Timing personalizado provisto" + ) MSG_HASH( - MSG_DISK_EJECTED, - "Expulsado" - ) + MSG_DECOMPRESSION_ALREADY_IN_PROGRESS, + "Descompresión en progreso" + ) MSG_HASH( - MSG_DOWNLOADING, - "Descargando" - ) + MSG_DECOMPRESSION_FAILED, + "Fallo al descomprimir" + ) MSG_HASH( - MSG_INDEX_FILE, - "indice" - ) + MSG_DETECTED_VIEWPORT_OF, + "Detectado viewport de" + ) MSG_HASH( - MSG_DOWNLOAD_FAILED, - "Descarga fallida" - ) + MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, + "No se encontró un parche válido" + ) MSG_HASH( - MSG_ERROR, - "Error" - ) + MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, + "Desconecte el dispositivo desde un puerto válido" + ) MSG_HASH( - MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, - "El núcleo Libretro necesita contenido, pero no fue provisto" - ) + MSG_DISK_CLOSED, + "Cerrado" + ) MSG_HASH( - MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT, - "El núcleo Libretro necesita contenido especial, pero no fue provisto" - ) + MSG_DISK_EJECTED, + "Expulsado" + ) MSG_HASH( - MSG_ERROR_PARSING_ARGUMENTS, - "Error analizando argumentos" - ) + MSG_DOWNLOADING, + "Descargando" + ) MSG_HASH( - MSG_ERROR_SAVING_CORE_OPTIONS_FILE, - "Error guardando archivo de opciones del núcleo" - ) + MSG_INDEX_FILE, + "indice" + ) MSG_HASH( - MSG_ERROR_SAVING_REMAP_FILE, - "Error guardando archivo de reasignación" - ) + MSG_DOWNLOAD_FAILED, + "Descarga fallida" + ) MSG_HASH( - MSG_ERROR_REMOVING_REMAP_FILE, - "Error eliminado archivo de reasignación" - ) + MSG_ERROR, + "Error" + ) MSG_HASH( - MSG_ERROR_SAVING_SHADER_PRESET, - "Error guardando shader preset" - ) + MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, + "El núcleo Libretro necesita contenido, pero no fue provisto" + ) MSG_HASH( - MSG_EXTERNAL_APPLICATION_DIR, - "Carpeta de aplicación externa" - ) + MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT, + "El núcleo Libretro necesita contenido especial, pero no fue provisto" + ) MSG_HASH( - MSG_EXTRACTING, - "Extrayendo" - ) + MSG_ERROR_PARSING_ARGUMENTS, + "Error analizando argumentos" + ) MSG_HASH( - MSG_EXTRACTING_FILE, - "Extrayendo archivo" - ) + MSG_ERROR_SAVING_CORE_OPTIONS_FILE, + "Error guardando archivo de opciones del núcleo" + ) MSG_HASH( - MSG_FAILED_SAVING_CONFIG_TO, - "Fallo al guardar configuración en" - ) + MSG_ERROR_SAVING_REMAP_FILE, + "Error guardando archivo de reasignación" + ) MSG_HASH( - MSG_FAILED_TO, - "Fallo al" - ) + MSG_ERROR_REMOVING_REMAP_FILE, + "Error eliminado archivo de reasignación" + ) MSG_HASH( - MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, - "Fallo al aceptar al espectador" - ) + MSG_ERROR_SAVING_SHADER_PRESET, + "Error guardando shader preset" + ) MSG_HASH( - MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, - "Fallo al reservar memoria para el contenido parcheado" - ) + MSG_EXTERNAL_APPLICATION_DIR, + "Carpeta de aplicación externa" + ) MSG_HASH( - MSG_FAILED_TO_APPLY_SHADER, - "Fallo al aplicar el shader" - ) + MSG_EXTRACTING, + "Extrayendo" + ) MSG_HASH( - MSG_FAILED_TO_BIND_SOCKET, - "Fallo al asignar el socket" - ) + MSG_EXTRACTING_FILE, + "Extrayendo archivo" + ) MSG_HASH( - MSG_FAILED_TO_CREATE_THE_DIRECTORY, - "Fallo al crear la carpeta" - ) + MSG_FAILED_SAVING_CONFIG_TO, + "Fallo al guardar configuración en" + ) MSG_HASH( - MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, - "Fallo al extraer el contenido desde el archivo comprimido" - ) + MSG_FAILED_TO, + "Fallo al" + ) MSG_HASH( - MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, - "Fallo al obtener el apodo del cliente" - ) + MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, + "Fallo al aceptar al espectador" + ) MSG_HASH( - MSG_FAILED_TO_LOAD, - "Fallo al cargar" - ) + MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, + "Fallo al reservar memoria para el contenido parcheado" + ) MSG_HASH( - MSG_FAILED_TO_LOAD_CONTENT, - "Fallo al cargar contenido" - ) + MSG_FAILED_TO_APPLY_SHADER, + "Fallo al aplicar el shader" + ) MSG_HASH( - MSG_FAILED_TO_LOAD_MOVIE_FILE, - "Fallo al cargar la película" - ) + MSG_FAILED_TO_BIND_SOCKET, + "Fallo al asignar el socket" + ) MSG_HASH( - MSG_FAILED_TO_LOAD_OVERLAY, - "Fallo al cargar la superposición" - ) + MSG_FAILED_TO_CREATE_THE_DIRECTORY, + "Fallo al crear la carpeta" + ) MSG_HASH( - MSG_FAILED_TO_LOAD_STATE, - "Fallo al cargar guardado de" - ) + MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, + "Fallo al extraer el contenido desde el archivo comprimido" + ) MSG_HASH( - MSG_FAILED_TO_OPEN_LIBRETRO_CORE, - "Fallo al abrir el núcleo Libretro" - ) + MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, + "Fallo al obtener el apodo del cliente" + ) MSG_HASH( - MSG_FAILED_TO_PATCH, - "Fallo el parcheado" - ) + MSG_FAILED_TO_LOAD, + "Fallo al cargar" + ) MSG_HASH( - MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT, - "Fallo al recibir el encabezado desde el cliente" - ) + MSG_FAILED_TO_LOAD_CONTENT, + "Fallo al cargar contenido" + ) MSG_HASH( - MSG_FAILED_TO_RECEIVE_NICKNAME, - "Fallo al recibir el apodo" - ) + MSG_FAILED_TO_LOAD_MOVIE_FILE, + "Fallo al cargar la película" + ) MSG_HASH( - MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST, - "Fallo al recibir el apodo del servidor" - ) + MSG_FAILED_TO_LOAD_OVERLAY, + "Fallo al cargar la superposición" + ) MSG_HASH( - MSG_FAILED_TO_RECEIVE_NICKNAME_SIZE_FROM_HOST, - "Fallo al recibir el tamaño del apodo del servidor" - ) + MSG_FAILED_TO_LOAD_STATE, + "Fallo al cargar guardado de" + ) MSG_HASH( - MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST, - "Fallo al recibir datos SaveRAM del servidor" - ) + MSG_FAILED_TO_OPEN_LIBRETRO_CORE, + "Fallo al abrir el núcleo Libretro" + ) MSG_HASH( - MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY, - "Fallo al sacar el disco de la bandeja" - ) + MSG_FAILED_TO_PATCH, + "Fallo el parcheado" + ) MSG_HASH( - MSG_FAILED_TO_REMOVE_TEMPORARY_FILE, - "Fallo al eliminar el archivo temporal" - ) + MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT, + "Fallo al recibir el encabezado desde el cliente" + ) MSG_HASH( - MSG_FAILED_TO_SAVE_SRAM, - "Fallo al guardar SaveRAM" - ) + MSG_FAILED_TO_RECEIVE_NICKNAME, + "Fallo al recibir el apodo" + ) MSG_HASH( - MSG_FAILED_TO_SAVE_STATE_TO, - "Fallo al guardar en" - ) + MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST, + "Fallo al recibir el apodo del servidor" + ) MSG_HASH( - MSG_FAILED_TO_SEND_NICKNAME, - "Fallo al enviar el apodo" - ) + MSG_FAILED_TO_RECEIVE_NICKNAME_SIZE_FROM_HOST, + "Fallo al recibir el tamaño del apodo del servidor" + ) MSG_HASH( - MSG_FAILED_TO_SEND_NICKNAME_SIZE, - "Fallo al enviar el tamaño del apodo" - ) + MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST, + "Fallo al recibir datos SaveRAM del servidor" + ) MSG_HASH( - MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT, - "Fallo al enviar el apodo al cliente" - ) + MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY, + "Fallo al sacar el disco de la bandeja" + ) MSG_HASH( - MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, - "Fallo al enviar el apodo al servidor" - ) + MSG_FAILED_TO_REMOVE_TEMPORARY_FILE, + "Fallo al eliminar el archivo temporal" + ) MSG_HASH( - MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, - "Fallo al enviar datos SaveRAM al cliente" - ) + MSG_FAILED_TO_SAVE_SRAM, + "Fallo al guardar SaveRAM" + ) MSG_HASH( - MSG_FAILED_TO_START_AUDIO_DRIVER, - "Fallo al iniciar el controlador de audio. Se continuará en silencio" - ) + MSG_FAILED_TO_SAVE_STATE_TO, + "Fallo al guardar en" + ) MSG_HASH( - MSG_FAILED_TO_START_MOVIE_RECORD, - "Fallo al iniciar clip de grabación" - ) + MSG_FAILED_TO_SEND_NICKNAME, + "Fallo al enviar el apodo" + ) MSG_HASH( - MSG_FAILED_TO_START_RECORDING, - "Fallo al iniciar grabación" - ) + MSG_FAILED_TO_SEND_NICKNAME_SIZE, + "Fallo al enviar el tamaño del apodo" + ) MSG_HASH( - MSG_FAILED_TO_TAKE_SCREENSHOT, - "Fallo al capturar pantalla" - ) + MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT, + "Fallo al enviar el apodo al cliente" + ) MSG_HASH( - MSG_FAILED_TO_UNDO_LOAD_STATE, - "Fallo al deshacer carga" - ) + MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, + "Fallo al enviar el apodo al servidor" + ) MSG_HASH( - MSG_FAILED_TO_UNDO_SAVE_STATE, - "Fallo al deshacer guardado" - ) + MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, + "Fallo al enviar datos SaveRAM al cliente" + ) MSG_HASH( - MSG_FAILED_TO_UNMUTE_AUDIO, - "Fallo al restablecer el audio" - ) + MSG_FAILED_TO_START_AUDIO_DRIVER, + "Fallo al iniciar el controlador de audio. Se continuará en silencio" + ) MSG_HASH( - MSG_FATAL_ERROR_RECEIVED_IN, - "Fatal error recibido en" - ) + MSG_FAILED_TO_START_MOVIE_RECORD, + "Fallo al iniciar clip de grabación" + ) MSG_HASH( - MSG_FILE_NOT_FOUND, - "Archivo no encontrado" - ) + MSG_FAILED_TO_START_RECORDING, + "Fallo al iniciar grabación" + ) MSG_HASH( - MSG_FOUND_AUTO_SAVESTATE_IN, - "Encontrado autoguardado en" - ) + MSG_FAILED_TO_TAKE_SCREENSHOT, + "Fallo al capturar pantalla" + ) MSG_HASH( - MSG_FOUND_DISK_LABEL, - "Encontrada la etiqueta del disco" - ) + MSG_FAILED_TO_UNDO_LOAD_STATE, + "Fallo al deshacer carga" + ) MSG_HASH( - MSG_FOUND_FIRST_DATA_TRACK_ON_FILE, - "Encontrada la primer pista de datos en el archivo" - ) + MSG_FAILED_TO_UNDO_SAVE_STATE, + "Fallo al deshacer guardado" + ) MSG_HASH( - MSG_FOUND_LAST_STATE_SLOT, - "Encontrada la ultima posición de guardado" - ) + MSG_FAILED_TO_UNMUTE_AUDIO, + "Fallo al restablecer el audio" + ) MSG_HASH( - MSG_FOUND_SHADER, - "Encontrado el shader" - ) + MSG_FATAL_ERROR_RECEIVED_IN, + "Error fatal recibido en" + ) MSG_HASH( - MSG_FRAMES, - "Frames" - ) + MSG_FILE_NOT_FOUND, + "Archivo no encontrado" + ) MSG_HASH( - MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT, - "Opciones especificas de juego encontradas en" - ) + MSG_FOUND_AUTO_SAVESTATE_IN, + "Encontrado autoguardado en" + ) MSG_HASH( - MSG_GOT_INVALID_DISK_INDEX, - "Indice de disco invalido" - ) + MSG_FOUND_DISK_LABEL, + "Encontrada la etiqueta del disco" + ) MSG_HASH( - MSG_GRAB_MOUSE_STATE, - "Capturar estado del ratón" - ) + MSG_FOUND_FIRST_DATA_TRACK_ON_FILE, + "Encontrada la primer pista de datos en el archivo" + ) MSG_HASH( - MSG_GAME_FOCUS_ON, - "Game focus ON" - ) + MSG_FOUND_LAST_STATE_SLOT, + "Encontrada la ultima posición de guardado" + ) MSG_HASH( - MSG_GAME_FOCUS_OFF, - "Game focus OFF" - ) + MSG_FOUND_SHADER, + "Encontrado el shader" + ) MSG_HASH( - MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, - "El núcleo Libretro esta renderizado por hardware. Debe usar grabaciones post-shaded" - ) + MSG_FRAMES, + "Frames" + ) MSG_HASH( - MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, - "El CRC32 inflado no concuerda" - ) + MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT, + "Opciones especificas de juego encontradas en" + ) MSG_HASH( - MSG_INPUT_CHEAT, - "Introducir truco" - ) + MSG_GOT_INVALID_DISK_INDEX, + "Indice de disco invalido" + ) MSG_HASH( - MSG_INPUT_CHEAT_FILENAME, - "Introducir nombre de archivo de truco" - ) + MSG_GRAB_MOUSE_STATE, + "Capturar estado del ratón" + ) MSG_HASH( - MSG_INPUT_PRESET_FILENAME, - "Introducir nombre de archivo del preset" - ) + MSG_GAME_FOCUS_ON, + "Game focus ON" + ) MSG_HASH( - MSG_INPUT_RENAME_ENTRY, - "Renombrar titulo" - ) + MSG_GAME_FOCUS_OFF, + "Game focus OFF" + ) MSG_HASH( - MSG_INTERFACE, - "Interfaz" - ) + MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, + "El núcleo Libretro esta renderizado por hardware. Debe usar grabaciones post-shaded" + ) MSG_HASH( - MSG_INTERNAL_STORAGE, - "Almacenamiento interno" - ) + MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, + "El CRC32 inflado no concuerda" + ) MSG_HASH( - MSG_REMOVABLE_STORAGE, - "Almacenamiento extraible" - ) + MSG_INPUT_CHEAT, + "Introducir truco" + ) MSG_HASH( - MSG_INVALID_NICKNAME_SIZE, - "Tamaño de apodo invalido" - ) + MSG_INPUT_CHEAT_FILENAME, + "Introducir nombre de archivo de truco" + ) MSG_HASH( - MSG_IN_BYTES, - "en bytes" - ) + MSG_INPUT_PRESET_FILENAME, + "Introducir nombre de archivo del preset" + ) MSG_HASH( - MSG_IN_GIGABYTES, - "en gigabytes" - ) + MSG_INPUT_RENAME_ENTRY, + "Renombrar titulo" + ) MSG_HASH( - MSG_IN_MEGABYTES, - "en megabytes" - ) + MSG_INTERFACE, + "Interfaz" + ) MSG_HASH( - MSG_LIBRETRO_ABI_BREAK, - "está compilado para otra versión de Libretro" - ) + MSG_INTERNAL_STORAGE, + "Almacenamiento interno" + ) MSG_HASH( - MSG_LIBRETRO_FRONTEND, - "Interfaz de usuario para Libretro" - ) + MSG_REMOVABLE_STORAGE, + "Almacenamiento extraible" + ) MSG_HASH( - MSG_LOADED_STATE_FROM_SLOT, - "Cargado guardado de la posición #%d" - ) + MSG_INVALID_NICKNAME_SIZE, + "Tamaño de apodo invalido" + ) MSG_HASH( - MSG_LOADED_STATE_FROM_SLOT_AUTO, - "Cargado guardado de la posición #-1 (auto)" - ) + MSG_IN_BYTES, + "en bytes" + ) MSG_HASH( - MSG_LOADING, - "Cargando" - ) + MSG_IN_GIGABYTES, + "en gigabytes" + ) MSG_HASH( - MSG_FIRMWARE, - "Faltan archivos de firmware" - ) + MSG_IN_MEGABYTES, + "en megabytes" + ) MSG_HASH( - MSG_LOADING_CONTENT_FILE, - "Cargando contenido" - ) + MSG_LIBRETRO_ABI_BREAK, + "está compilado para otra versión de Libretro" + ) MSG_HASH( - MSG_LOADING_HISTORY_FILE, - "Cargando historial" - ) + MSG_LIBRETRO_FRONTEND, + "Interfaz de usuario para Libretro" + ) MSG_HASH( - MSG_LOADING_STATE, - "Cargando estado" - ) + MSG_LOADED_STATE_FROM_SLOT, + "Cargado guardado de la posición #%d" + ) MSG_HASH( - MSG_MEMORY, - "Memoria" - ) + MSG_LOADED_STATE_FROM_SLOT_AUTO, + "Cargado guardado de la posición #-1 (auto)" + ) MSG_HASH( - MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, - "La película no es un archivo BSV1 válido" - ) + MSG_LOADING, + "Cargando" + ) MSG_HASH( - MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, - "El formato de la película parece tener una versión diferente de serializer. Probablemente fallará" - ) + MSG_FIRMWARE, + "Faltan archivos de firmware" + ) MSG_HASH( - MSG_MOVIE_PLAYBACK_ENDED, - "Finalizó la reproducción" - ) + MSG_LOADING_CONTENT_FILE, + "Cargando contenido" + ) MSG_HASH( - MSG_MOVIE_RECORD_STOPPED, - "Deteniendo la grabación" - ) + MSG_LOADING_HISTORY_FILE, + "Cargando historial" + ) MSG_HASH( - MSG_NETPLAY_FAILED, - "Fallo al iniciar juego en red" - ) + MSG_LOADING_STATE, + "Cargando estado" + ) MSG_HASH( - MSG_NO_CONTENT_STARTING_DUMMY_CORE, - "No hay contenido, iniciando núcleo vacío" - ) + MSG_MEMORY, + "Memoria" + ) MSG_HASH( - MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, - "No hay guardado sobrescrito todavía" - ) + MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, + "La película no es un archivo BSV1 válido" + ) MSG_HASH( - MSG_NO_STATE_HAS_BEEN_LOADED_YET, - "No hay guardado cargado todavía" - ) + MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, + "El formato de la película parece tener una versión diferente de serializer. Probablemente fallará" + ) MSG_HASH( - MSG_OVERRIDES_ERROR_SAVING, - "Error guardando personalizaciones" - ) + MSG_MOVIE_PLAYBACK_ENDED, + "Finalizó la reproducción" + ) MSG_HASH( - MSG_OVERRIDES_SAVED_SUCCESSFULLY, - "Personalizaciones guardadas exitosamente" - ) + MSG_MOVIE_RECORD_STOPPED, + "Deteniendo la grabación" + ) MSG_HASH( - MSG_PAUSED, - "Pausado" - ) + MSG_NETPLAY_FAILED, + "Fallo al iniciar juego en red" + ) MSG_HASH( - MSG_PROGRAM, - "RetroArch" - ) + MSG_NO_CONTENT_STARTING_DUMMY_CORE, + "No hay contenido, iniciando núcleo vacío" + ) MSG_HASH( - MSG_READING_FIRST_DATA_TRACK, - "Leyendo la primer pista de datos..." - ) + MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, + "No hay guardado sobrescrito todavía" + ) MSG_HASH( - MSG_RECEIVED, - "recibido" - ) + MSG_NO_STATE_HAS_BEEN_LOADED_YET, + "No hay guardado cargado todavía" + ) MSG_HASH( - MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, - "Grabación terminada debido al cambio de tamaño" - ) + MSG_OVERRIDES_ERROR_SAVING, + "Error guardando personalizaciones" + ) MSG_HASH( - MSG_RECORDING_TO, - "Grabando en" - ) + MSG_OVERRIDES_SAVED_SUCCESSFULLY, + "Personalizaciones guardadas exitosamente" + ) MSG_HASH( - MSG_REDIRECTING_CHEATFILE_TO, - "Redirigiendo archivo de trucos a" - ) + MSG_PAUSED, + "Pausado" + ) MSG_HASH( - MSG_REDIRECTING_SAVEFILE_TO, - "Redirigiendo archivo de guardado a" - ) + MSG_PROGRAM, + "RetroArch" + ) MSG_HASH( - MSG_REDIRECTING_SAVESTATE_TO, - "Redirigiendo archivo de guardado rápido a" - ) + MSG_READING_FIRST_DATA_TRACK, + "Leyendo la primer pista de datos..." + ) MSG_HASH( - MSG_REMAP_FILE_SAVED_SUCCESSFULLY, - "Reasignaciones guardadas exitosamente" - ) + MSG_RECEIVED, + "recibido" + ) MSG_HASH( - MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, - "Reasignaciones eliminadas exitosamente" - ) + MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, + "Grabación terminada debido al cambio de tamaño" + ) MSG_HASH( - MSG_REMOVED_DISK_FROM_TRAY, - "Quitado el disco de la bandeja" - ) + MSG_RECORDING_TO, + "Grabando en" + ) MSG_HASH( - MSG_REMOVING_TEMPORARY_CONTENT_FILE, - "Eliminando el contenido temporal" - ) + MSG_REDIRECTING_CHEATFILE_TO, + "Redirigiendo archivo de trucos a" + ) MSG_HASH( - MSG_RESET, - "Reset" - ) + MSG_REDIRECTING_SAVEFILE_TO, + "Redirigiendo archivo de guardado a" + ) MSG_HASH( - MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT, - "Reiniciando grabación por reinicio del controlador" - ) + MSG_REDIRECTING_SAVESTATE_TO, + "Redirigiendo archivo de guardado rápido a" + ) MSG_HASH( - MSG_RESTORED_OLD_SAVE_STATE, - "Restaurado antiguo guardado rápido" - ) + MSG_REMAP_FILE_SAVED_SUCCESSFULLY, + "Reasignaciones guardadas exitosamente" + ) MSG_HASH( - MSG_RESTORING_DEFAULT_SHADER_PRESET_TO, - "Shaders: restaurado el preset por defecto en" - ) + MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, + "Reasignaciones eliminadas exitosamente" + ) MSG_HASH( - MSG_REVERTING_SAVEFILE_DIRECTORY_TO, - "Revirtiendo la carpeta de guardado a" - ) + MSG_REMOVED_DISK_FROM_TRAY, + "Quitado el disco de la bandeja" + ) MSG_HASH( - MSG_REVERTING_SAVESTATE_DIRECTORY_TO, - "Revirtiendo la carpeta de guardado rápido a" - ) + MSG_REMOVING_TEMPORARY_CONTENT_FILE, + "Eliminando el contenido temporal" + ) MSG_HASH( - MSG_REWINDING, - "Rebobinando" - ) + MSG_RESET, + "Reset" + ) MSG_HASH( - MSG_REWIND_INIT, - "Iniciando buffer de rebobinado de" - ) + MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT, + "Reiniciando grabación por reinicio del controlador" + ) MSG_HASH( - MSG_REWIND_INIT_FAILED, - "Fallo al iniciar el buffer. El rebobinado se desactivará" - ) + MSG_RESTORED_OLD_SAVE_STATE, + "Restaurado antiguo guardado rápido" + ) MSG_HASH( - MSG_REWIND_INIT_FAILED_THREADED_AUDIO, - "La implementación usa audio por hilos. No se puede usar rebobinado" - ) + MSG_RESTORING_DEFAULT_SHADER_PRESET_TO, + "Shaders: restaurado el preset por defecto en" + ) MSG_HASH( - MSG_REWIND_REACHED_END, - "Fin del buffer de rebobinado" - ) + MSG_REVERTING_SAVEFILE_DIRECTORY_TO, + "Revirtiendo la carpeta de guardado a" + ) MSG_HASH( - MSG_SAVED_NEW_CONFIG_TO, - "Guardada nueva configuración en" - ) + MSG_REVERTING_SAVESTATE_DIRECTORY_TO, + "Revirtiendo la carpeta de guardado rápido a" + ) MSG_HASH( - MSG_SAVED_STATE_TO_SLOT, - "Guardado a la posición #%d" - ) + MSG_REWINDING, + "Rebobinando" + ) MSG_HASH( - MSG_SAVED_STATE_TO_SLOT_AUTO, - "Guardado #-1 (auto)" - ) + MSG_REWIND_INIT, + "Iniciando buffer de rebobinado de" + ) MSG_HASH( - MSG_SAVED_SUCCESSFULLY_TO, - "Guardado exitosamente en" - ) + MSG_REWIND_INIT_FAILED, + "Fallo al iniciar el buffer. El rebobinado se desactivará" + ) MSG_HASH( - MSG_SAVING_RAM_TYPE, - "Guardando RAM" - ) + MSG_REWIND_INIT_FAILED_THREADED_AUDIO, + "La implementación usa audio por hilos. No se puede usar rebobinado" + ) MSG_HASH( - MSG_SAVING_STATE, - "Guardando" - ) + MSG_REWIND_REACHED_END, + "Fin del buffer de rebobinado" + ) MSG_HASH( - MSG_SCANNING, - "Escaneando..." - ) + MSG_SAVED_NEW_CONFIG_TO, + "Guardada nueva configuración en" + ) MSG_HASH( - MSG_SCANNING_OF_DIRECTORY_FINISHED, - "Escaneo de carpeta finalizado" - ) + MSG_SAVED_STATE_TO_SLOT, + "Guardado a la posición #%d" + ) MSG_HASH( - MSG_SENDING_COMMAND, - "Enviando comando" - ) + MSG_SAVED_STATE_TO_SLOT_AUTO, + "Guardado #-1 (auto)" + ) MSG_HASH( - MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED, - "Varios parches están explicitamente definidos, ignorando todos..." - ) + MSG_SAVED_SUCCESSFULLY_TO, + "Guardado exitosamente en" + ) MSG_HASH( - MSG_SHADER, - "Shader" - ) + MSG_SAVING_RAM_TYPE, + "Guardando RAM" + ) MSG_HASH( - MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, - "Shader preset guardado exitosamente" - ) + MSG_SAVING_STATE, + "Guardando" + ) MSG_HASH( - MSG_SKIPPING_SRAM_LOAD, - "Saltando carga de SaveRAM" - ) + MSG_SCANNING, + "Escaneando..." + ) MSG_HASH( - MSG_SLOW_MOTION, - "Cámara lenta" - ) + MSG_SCANNING_OF_DIRECTORY_FINISHED, + "Escaneo de carpeta finalizado" + ) MSG_HASH( - MSG_FAST_FORWARD, - "Avance rápido" - ) + MSG_SENDING_COMMAND, + "Enviando comando" + ) MSG_HASH( - MSG_SLOW_MOTION_REWIND, - "Rebobinado lento" - ) + MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED, + "Varios parches están explicitamente definidos, ignorando todos..." + ) MSG_HASH( - MSG_SRAM_WILL_NOT_BE_SAVED, - "SaveRAM no se guardará" - ) + MSG_SHADER, + "Shader" + ) MSG_HASH( - MSG_STARTING_MOVIE_PLAYBACK, - "Iniciando reproducción de película" - ) + MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, + "Shader preset guardado exitosamente" + ) MSG_HASH( - MSG_STARTING_MOVIE_RECORD_TO, - "Iniciando grabación de película en" - ) + MSG_SKIPPING_SRAM_LOAD, + "Saltando carga de SaveRAM" + ) MSG_HASH( - MSG_STATE_SIZE, - "Tamaño del guardado" - ) + MSG_SLOW_MOTION, + "Cámara lenta" + ) MSG_HASH( - MSG_STATE_SLOT, - "Posición de guardado" - ) + MSG_FAST_FORWARD, + "Avance rápido" + ) MSG_HASH( - MSG_TAKING_SCREENSHOT, - "Capturando pantalla" - ) + MSG_SLOW_MOTION_REWIND, + "Rebobinado lento" + ) MSG_HASH( - MSG_TO, - "en" - ) + MSG_SRAM_WILL_NOT_BE_SAVED, + "SaveRAM no se guardará" + ) MSG_HASH( - MSG_UNDID_LOAD_STATE, - "Deshecha la carga" - ) + MSG_STARTING_MOVIE_PLAYBACK, + "Iniciando reproducción de película" + ) MSG_HASH( - MSG_UNDOING_SAVE_STATE, - "Deshaciendo el guardado" - ) + MSG_STARTING_MOVIE_RECORD_TO, + "Iniciando grabación de película en" + ) MSG_HASH( - MSG_UNKNOWN, - "Desconocido" - ) + MSG_STATE_SIZE, + "Tamaño del guardado" + ) MSG_HASH( - MSG_UNPAUSED, - "Despausado" - ) + MSG_STATE_SLOT, + "Posición de guardado" + ) MSG_HASH( - MSG_UNRECOGNIZED_COMMAND, - "Comando no reconocido" - ) + MSG_TAKING_SCREENSHOT, + "Capturando pantalla" + ) MSG_HASH( - MSG_USING_CORE_NAME_FOR_NEW_CONFIG, - "Usando el nombre del núcleo para la nueva configuración" - ) + MSG_TO, + "en" + ) MSG_HASH( - MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, - "Usando núcleo vacío. Saltando grabación" - ) + MSG_UNDID_LOAD_STATE, + "Deshecha la carga" + ) MSG_HASH( - MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, - "Conecte el dispositivo a un puerto valido" - ) + MSG_UNDOING_SAVE_STATE, + "Deshaciendo el guardado" + ) MSG_HASH( - MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, - "Desconectando el dispositivo del puerto" - ) + MSG_UNKNOWN, + "Desconocido" + ) MSG_HASH( - MSG_VALUE_REBOOTING, - "Reiniciando..." - ) + MSG_UNPAUSED, + "Despausado" + ) MSG_HASH( - MSG_VALUE_SHUTTING_DOWN, - "Apagando..." - ) + MSG_UNRECOGNIZED_COMMAND, + "Comando no reconocido" + ) MSG_HASH( - MSG_VERSION_OF_LIBRETRO_API, - "Versión de la API Libretro" - ) + MSG_USING_CORE_NAME_FOR_NEW_CONFIG, + "Usando el nombre del núcleo para la nueva configuración" + ) MSG_HASH( - MSG_VIEWPORT_SIZE_CALCULATION_FAILED, - "Fallo al calcular de la ventana! Se continuará usando datos en bruto. Probablemente no funcionará bien" - ) + MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, + "Usando núcleo vacío. Saltando grabación" + ) MSG_HASH( - MSG_VIRTUAL_DISK_TRAY, - "Bandeja de discos virtual" - ) + MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, + "Conecte el dispositivo a un puerto valido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_LATENCY, - "Latencia de audio deseada en milisegundos. Puede no ser honrada si el controlador no puede proveerla" - ) + MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, + "Desconectando el dispositivo del puerto" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_MUTE, - "Silencia el audio" - ) + MSG_VALUE_REBOOTING, + "Reiniciando..." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, - "Ayuda a suavizar imperfecciones de timing al sincronizar audio y video. desactivarlo hace casi imposible una sincronía correcta" - ) + MSG_VALUE_SHUTTING_DOWN, + "Apagando..." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CAMERA_ALLOW, - "Habilitar o deshabilitar el acceso de los núcleos a la cámara" - ) + MSG_VERSION_OF_LIBRETRO_API, + "Versión de la API Libretro" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LOCATION_ALLOW, - "Habilitar o deshabilitar al núcleo a usar los servicios de ubicación" - ) + MSG_VIEWPORT_SIZE_CALCULATION_FAILED, + "Fallo al calcular de la ventana! Se continuará usando datos en bruto. Probablemente no funcionará bien" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, - "Máxima cantidad de usuarios a soportar por RetroArch" - ) + MSG_VIRTUAL_DISK_TRAY, + "Bandeja de discos virtual" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, - "Influencia como el sondeo es hecho dentro de RetroArch. 'Temprano' o 'Tarde' pueden resultar en menor latencia, dependiendo de su configuración" - ) + MENU_ENUM_SUBLABEL_AUDIO_LATENCY, + "Latencia de audio deseada en milisegundos. Puede no ser honrada si el controlador no puede proveerla" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, - "Permite a cualquier usuario a controlar el menú. Si se desactiva solo podrá hacerlo el usuario 1" - ) + MENU_ENUM_SUBLABEL_AUDIO_MUTE, + "Silencia el audio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_VOLUME, - "0 dB es normal, donde no se aplica ganancia" - ) + MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, + "Ayuda a suavizar imperfecciones de timing al sincronizar audio y video. desactivarlo hace casi imposible una sincronía correcta" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_WASAPI_EXCLUSIVE_MODE, - "Permite al controlador WASAPI tomar control exclusivo del disp. de audio. Al deshabilitarlo se usará el modo compartido" - ) + MENU_ENUM_SUBLABEL_CAMERA_ALLOW, + "Habilitar o deshabilitar el acceso de los núcleos a la cámara" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_WASAPI_FLOAT_FORMAT, - "Usar formato de punto flotante en WASAPI, Su dispositivo debe soportarlo" - ) + MENU_ENUM_SUBLABEL_LOCATION_ALLOW, + "Habilitar o deshabilitar al núcleo a usar los servicios de ubicación" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH, - "El tamaño del buffer intermedio (en frames) al usar WASAPI en modo compartido" - ) + MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, + "Máxima cantidad de usuarios a soportar por RetroArch" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_SYNC, - "Sincronizar audio. Recomendado" - ) + MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, + "Influencia como el sondeo es hecho dentro de RetroArch. 'Temprano' o 'Tarde' pueden resultar en menor latencia, dependiendo de su configuración" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, - "Cuanto debe mover la palanca para ser detectada. Evita movimientos indeseados en los mandos que no vuelven perfectamente al centro" - ) + MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, + "Permite a cualquier usuario a controlar el menú. Si se desactiva solo podrá hacerlo el usuario 1" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, - "Cantidad de segundos a esperar hasta la siguiente asignación" - ) + MENU_ENUM_SUBLABEL_AUDIO_VOLUME, + "0 dB es normal, donde no se aplica ganancia" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_BIND_HOLD, - "Cantidad de segundos a mantener una entrada para asignarla" - ) + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_EXCLUSIVE_MODE, + "Permite al controlador WASAPI tomar control exclusivo del disp. de audio. Al deshabilitarlo se usará el modo compartido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Periodo entre pulsación de los botones turbo (en frames)" - ) + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_FLOAT_FORMAT, + "Usar formato de punto flotante en WASAPI, Su dispositivo debe soportarlo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Cuanto debe durar la pulsación de los botones turbo (en frames)" - ) + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH, + "El tamaño del buffer intermedio (en frames) al usar WASAPI en modo compartido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VSYNC, - "Sincroniza la salida de la placa de video al refresco de la pantalla. Recomendado" - ) + MENU_ENUM_SUBLABEL_AUDIO_SYNC, + "Sincronizar audio. Recomendado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, - "Permitir a los núcleos rotar la pantalla. Desactivarlo es útil cuando se puede girar el dispositivo manualmente" - ) + MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, + "Cuanto debe mover la palanca para ser detectada. Evita movimientos indeseados en los mandos que no vuelven perfectamente al centro" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN, - "Activarlo previene que algunos núcleos con función de apagado cierren RetroArch, en lugar de eso se cargará un núcleo vacío" - ) + MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, + "Cantidad de segundos a esperar hasta la siguiente asignación" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, - "Verificar que el firmware necesario este disponible antes de cargar el contenido" - ) + MENU_ENUM_SUBLABEL_INPUT_BIND_HOLD, + "Cantidad de segundos a mantener una entrada para asignarla" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, - "Tasa de refresco vertical de su pantalla. Usada para calcular la velocidad de audio. Nota: Se ignorará si 'Video por hilos' esta activado" - ) + MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, + "Periodo entre pulsación de los botones turbo (en frames)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_ENABLE, - "Activar salida de audio" - ) + MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, + "Cuanto debe durar la pulsación de los botones turbo (en frames)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, - "El máximo cambio en la velocidad de audio. Incrementarlo permite grandes cambios de timing a costa del tono de audio (Ej. Núcleos PAL en pantallas NTSC)" - ) + MENU_ENUM_SUBLABEL_VIDEO_VSYNC, + "Sincroniza la salida de la placa de video al refresco de la pantalla. Recomendado" + ) MSG_HASH( - MSG_FAILED, - "Fallo" - ) + MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, + "Permitir a los núcleos rotar la pantalla. Desactivarlo es útil cuando se puede girar el dispositivo manualmente" + ) MSG_HASH( - MSG_SUCCEEDED, - "Éxito" - ) + MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN, + "Activarlo previene que algunos núcleos con función de apagado cierren RetroArch, en lugar de eso se cargará un núcleo vacío" + ) MSG_HASH( - MSG_DEVICE_NOT_CONFIGURED, - "no configurado" - ) + MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, + "Verificar que el firmware necesario este disponible antes de cargar el contenido" + ) MSG_HASH( - MSG_DEVICE_NOT_CONFIGURED_FALLBACK, - "no configurado, usando respaldo" - ) + MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, + "Tasa de refresco vertical de su pantalla. Usada para calcular la velocidad de audio. Nota: Se ignorará si 'Video por hilos' esta activado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, - "Base de datos: Lista cursor" - ) + MENU_ENUM_SUBLABEL_AUDIO_ENABLE, + "Activar salida de audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DEVELOPER, - "Base de datos - Filtro : Desarrollador" - ) + MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, + "El máximo cambio en la velocidad de audio. Incrementarlo permite grandes cambios de timing a costa del tono de audio (Ej. Núcleos PAL en pantallas NTSC)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PUBLISHER, - "Base de datos - Filtro : Distribuidora" - ) + MSG_FAILED, + "Fallo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISABLED, - "Desactivado" - ) + MSG_SUCCEEDED, + "Éxito" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ENABLED, - "Activado" - ) + MSG_DEVICE_NOT_CONFIGURED, + "no configurado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_PATH, - "Ruta del historial" - ) + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "no configurado, usando respaldo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ORIGIN, - "Base de datos - Filtro : Origen" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, + "Base de datos: Lista cursor" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_FRANCHISE, - "Base de datos - Filtro : Franquicia" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DEVELOPER, + "Base de datos - Filtro : Desarrollador" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ESRB_RATING, - "Base de datos - Filtro : ESRB Rating" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PUBLISHER, + "Base de datos - Filtro : Distribuidora" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ELSPA_RATING, - "Base de datos - Filtro : ELSPA Rating" - ) + MENU_ENUM_LABEL_VALUE_DISABLED, + "Desactivado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PEGI_RATING, - "Base de datos - Filtro : PEGI Rating" - ) + MENU_ENUM_LABEL_VALUE_ENABLED, + "Activado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_CERO_RATING, - "Base de datos - Filtro : CERO Rating" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_PATH, + "Ruta del historial" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_BBFC_RATING, - "Base de datos - Filtro : BBFC Rating" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ORIGIN, + "Base de datos - Filtro : Origen" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_MAX_USERS, - "Base de datos - Filtro : Máximo de usuarios" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_FRANCHISE, + "Base de datos - Filtro : Franquicia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_MONTH, - "Base de datos - Filtro : Lanzamiento por mes" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ESRB_RATING, + "Base de datos - Filtro : ESRB Rating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_YEAR, - "Base de datos - Filtro : Lanzamiento por año" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ELSPA_RATING, + "Base de datos - Filtro : ELSPA Rating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, - "Base de datos - Filtro : número de la revista Edge" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PEGI_RATING, + "Base de datos - Filtro : PEGI Rating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, - "Base de datos - Filtro : Rating de la revista Edge" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_CERO_RATING, + "Base de datos - Filtro : CERO Rating" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, - "Info de base de datos" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_BBFC_RATING, + "Base de datos - Filtro : BBFC Rating" + ) MSG_HASH( - MSG_WIFI_SCAN_COMPLETE, - "Escaneo Wi-Fi completo" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_MAX_USERS, + "Base de datos - Filtro : Máximo de usuarios" + ) MSG_HASH( - MSG_SCANNING_WIRELESS_NETWORKS, - "Escaneando redes inalambricas..." - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_MONTH, + "Base de datos - Filtro : Lanzamiento por mes" + ) MSG_HASH( - MSG_NETPLAY_LAN_SCAN_COMPLETE, - "Juego en red escaneo completo" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_YEAR, + "Base de datos - Filtro : Lanzamiento por año" + ) MSG_HASH( - MSG_NETPLAY_LAN_SCANNING, - "Escaneando en busca de anfitriones de juego en red..." - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, + "Base de datos - Filtro : número de la revista Edge" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, - "Pausar gameplay cuando RetroArch no es la ventana activa" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, + "Base de datos - Filtro : Rating de la revista Edge" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, - "Activar o desactivar composición (Solo Windows)" - ) + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, + "Info de base de datos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, - "Activar o desactivar lista de elementos recientes para juegos, imágenes, música, y videos" - ) + MSG_WIFI_SCAN_COMPLETE, + "Escaneo Wi-Fi completo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, - "Limitar el número de entradas en la lista de elementos recientes" - ) + MSG_SCANNING_WIRELESS_NETWORKS, + "Escaneando redes inalambricas..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, - "Controles de menú unificados" - ) + MSG_NETPLAY_LAN_SCAN_COMPLETE, + "Juego en red escaneo completo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, - "Usar los mismos controles para el menú y el juego. Aplica al teclado" - ) + MSG_NETPLAY_LAN_SCANNING, + "Escaneando en busca de anfitriones de juego en red..." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, - "Mostrar mensajes en pantalla" - ) + MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, + "Pausar gameplay cuando RetroArch no es la ventana activa" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, - "Usuario %d Remoto Activado" - ) + MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, + "Activar o desactivar composición (Solo Windows)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, - "Mostrar nivel de batería" - ) + MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, + "Activar o desactivar lista de elementos recientes para juegos, imágenes, música, y videos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SELECT_FILE, - "Seleccionar archivo" - ) + MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, + "Limitar el número de entradas en la lista de elementos recientes" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SELECT_FROM_COLLECTION, - "Seleccionar de la colección" - ) + MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, + "Controles de menú unificados" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FILTER, - "Filtro" - ) + MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, + "Usar los mismos controles para el menú y el juego. Aplica al teclado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCALE, - "Escalar" - ) + MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, + "Mostrar mensajes en pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, - "El juego en red comenzará cuando se cargue el contenido" - ) + MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, + "Usuario %d Remoto Activado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, - "No se encontró el núcleo o contenido, cargue manualmente" - ) + MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, + "Mostrar nivel de batería" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, - "Ver URLs" - ) + MENU_ENUM_LABEL_VALUE_SELECT_FILE, + "Seleccionar archivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BROWSE_URL, - "Ver URL" - ) + MENU_ENUM_LABEL_VALUE_SELECT_FROM_COLLECTION, + "Seleccionar de la colección" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BROWSE_START, - "Iniciar" - ) + MENU_ENUM_LABEL_VALUE_FILTER, + "Filtro" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, - "Bokeh" - ) + MENU_ENUM_LABEL_VALUE_SCALE, + "Escalar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOWFLAKE, - "Snowflake" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, + "El juego en red comenzará cuando se cargue el contenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, - "Actualizar lista de salas" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, + "No se encontró el núcleo o contenido, cargue manualmente" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, - "Apodo: %s" - ) + MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, + "Ver URLs" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, - "Apodo (lan): %s" - ) + MENU_ENUM_LABEL_VALUE_BROWSE_URL, + "Ver URL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, - "Contenido compatible encontrado" - ) + MENU_ENUM_LABEL_VALUE_BROWSE_START, + "Iniciar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, - "Corta unos pocos pixeles de los bordes de la imagen que normalmente los desarrolladores dejan en blanco o con basura" - ) + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, + "Bokeh" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, - "Aplicar un pequeño desenfoque a la imagen para borrar los bordes de los pixeles. Esta opción tiene muy poco impacto en el rendimiento" - ) + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOWFLAKE, + "Snowflake" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FILTER, - "Aplicar un filtro de video con la CPU. Nota: Puede tener un alto coste de rendimiento. Algunos filtros solo funcionan con núcleos que usan 16 o 32bit de color" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, + "Actualizar lista de salas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, - "Nombre de usuario de su cuenta de RetroAchievements" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, + "Apodo: %s" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, - "Contraseña de su cuenta de RetroAchievements" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, + "Apodo (lan): %s" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, - "Ingrese su apodo. Esto sera usado para las sesiones de juego en red" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, + "Contenido compatible encontrado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, - "Capturar la imagen con los filtros (no shaders)" - ) + MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, + "Corta unos pocos pixeles de los bordes de la imagen que normalmente los desarrolladores dejan en blanco o con basura" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_LIST, - "Seleccionar que núcleo usar" - ) + MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, + "Aplicar un pequeño desenfoque a la imagen para borrar los bordes de los pixeles. Esta opción tiene muy poco impacto en el rendimiento" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, - "Seleccionar que contenido iniciar" - ) + MENU_ENUM_SUBLABEL_VIDEO_FILTER, + "Aplicar un filtro de video con la CPU. Nota: Puede tener un alto coste de rendimiento. Algunos filtros solo funcionan con núcleos que usan 16 o 32bit de color" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, - "Mostrar interfaces de red e IPs asociadas" - ) + MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, + "Nombre de usuario de su cuenta de RetroAchievements" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, - "Mostrar información especifica del dispositivo" - ) + MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, + "Contraseña de su cuenta de RetroAchievements" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUIT_RETROARCH, - "Salir del programa" - ) + MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, + "Ingrese su apodo. Esto sera usado para las sesiones de juego en red" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, - "Establece el ancho de la ventana. Al dejarlo en 0 hará que intente ser lo mas grande posible" - ) + MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, + "Capturar la imagen con los filtros (no shaders)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, - "Establece el alto de la ventana. Al dejarlo en 0 hará que intente ser lo mas grande posible" - ) + MENU_ENUM_SUBLABEL_CORE_LIST, + "Seleccionar que núcleo usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, - "Establece el ancho en pantalla completa. Al dejarlo en 0 se usará la resolución del escritorio" - ) + MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, + "Seleccionar que contenido iniciar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, - "Establece el alto en pantalla completa. Al dejarlo en 0 se usará la resolución del escritorio" - ) + MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, + "Mostrar interfaces de red e IPs asociadas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, - "Especificar posición sobre eje X para el texto en pantalla" - ) + MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, + "Mostrar información especifica del dispositivo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, - "Especificar posición sobre eje Y para el texto en pantalla" - ) + MENU_ENUM_SUBLABEL_QUIT_RETROARCH, + "Salir del programa" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Especificar el tamaño de letra en puntos" - ) + MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, + "Establece el ancho de la ventana. Al dejarlo en 0 hará que intente ser lo mas grande posible" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, - "Ocultar la superposición en el menú, mostrarla al salir del menú" - ) + MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, + "Establece el alto de la ventana. Al dejarlo en 0 hará que intente ser lo mas grande posible" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, - "Mostrar pulsaciones en los controles en pantalla" - ) + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, + "Establece el ancho en pantalla completa. Al dejarlo en 0 se usará la resolución del escritorio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, - "Seleccionar el puerto en que los controles en pantalla escucharán las pulsaciones" - ) + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, + "Establece el alto en pantalla completa. Al dejarlo en 0 se usará la resolución del escritorio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, - "El contenido escaneado aparecerá aquí" - ) + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, + "Especificar posición sobre eje X para el texto en pantalla" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, - "Escalar en múltiplos enteros. El tamaño base dependerá del sistema usado. Si 'Forzar aspecto' no esta activado, X e Y serán escalados individualmente" - ) + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, + "Especificar posición sobre eje Y para el texto en pantalla" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_GPU_SCREENSHOT, - "Capturas de pantalla de GPU con shaders si está disponible" - ) + MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, + "Especificar el tamaño de letra en puntos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_ROTATION, - "Fuerza una cierta rotación de la pantalla. La rotación se añade a la impuesta por el núcleo" - ) + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, + "Ocultar la superposición en el menú, mostrarla al salir del menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FORCE_SRGB_DISABLE, - "Desactiva forzadamente el soporte de FBO sRGB. Para algunos controladores Intel OpenGL en Windows con problemas" - ) + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Mostrar pulsaciones en los controles en pantalla" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN, - "Puede ser anulado por un argumento en la linea de comandos" - ) + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Seleccionar el puerto en que los controles en pantalla escucharán las pulsaciones" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_WINDOWED_FULLSCREEN, - "Preferir uso de ventana sin bordes a pantalla completa" - ) + MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, + "El contenido escaneado aparecerá aquí" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_GPU_RECORD, - "Graba la salida de GPU con shaders si está disponible" - ) + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, + "Escalar en múltiplos enteros. El tamaño base dependerá del sistema usado. Si 'Forzar aspecto' no esta activado, X e Y serán escalados individualmente" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, - "Al hacer un guardado rápido, el indice es automáticamente incrementado antes de guardar. Al cargar contenido, el indice será el mayor existente" - ) + MENU_ENUM_SUBLABEL_VIDEO_GPU_SCREENSHOT, + "Capturas de pantalla de GPU con shaders si está disponible" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, - "Bloquear el guardado de SaveRAM de ser sobrescrito al cargar guardados rápidos. Puede causar problemas" - ) + MENU_ENUM_SUBLABEL_VIDEO_ROTATION, + "Fuerza una cierta rotación de la pantalla. La rotación se añade a la impuesta por el núcleo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_FASTFORWARD_RATIO, - "La máxima velocidad del avance rápido (Ej: 5.0x para un juego de 60fps = 300 fps). Si es 0 no habrá limite" - ) + MENU_ENUM_SUBLABEL_VIDEO_FORCE_SRGB_DISABLE, + "Desactiva forzadamente el soporte de FBO sRGB. Para algunos controladores Intel OpenGL en Windows con problemas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, - "Al usar cámara lenta, el contenido se ralentizará el factor especificado" - ) + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN, + "Puede ser anulado por un argumento en la linea de comandos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_ENABLED, - "Ejecutar la logica del núcleo uno o mas frames por adelentado, y decidir cuando adelantar basados en las pulsaciones del control, esto puede reducir la latencia de entrada percibida, eliminando el lag interno de la consola o juego emulado" - ) + MENU_ENUM_SUBLABEL_VIDEO_WINDOWED_FULLSCREEN, + "Preferir uso de ventana sin bordes a pantalla completa" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_FRAMES, - "El número de frames que el núcleo irá adelantado, si excedes el número de frames de lag internos del juego, puede causar tirones (jitter)" - ) + MENU_ENUM_SUBLABEL_VIDEO_GPU_RECORD, + "Graba la salida de GPU con shaders si está disponible" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_SECONDARY_INSTANCE, - "Usar una segunda instancia del núcleo para adelantarse (RunAhead). Previene problemas de audio causados por las cargas de estado" - ) + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, + "Al hacer un guardado rápido, el indice es automáticamente incrementado antes de guardar. Al cargar contenido, el indice será el mayor existente" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS, - "Oculta el mensaje de advertencia que aparece al usar RunAhead si el núcleo no soporta guardar el estado (savestates)" - ) + MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, + "Bloquear el guardado de SaveRAM de ser sobrescrito al cargar guardados rápidos. Puede causar problemas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_REWIND_ENABLE, - "Habilita el rebobinado. Tendrá un impacto en el rendimiento del juego" - ) + MENU_ENUM_SUBLABEL_FASTFORWARD_RATIO, + "La máxima velocidad del avance rápido (Ej: 5.0x para un juego de 60fps = 300 fps). Si es 0 no habrá limite" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, - "Rebobinar un determinado número de frames a la vez, para aumentar la velocidad del rebobinado" - ) + MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, + "Al usar cámara lenta, el contenido se ralentizará el factor especificado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE, - "La cantidad de memoria (en MB) a reservar para el búfer de rebobinado. Aumentar esto aumentará el largo del historial de rebobinado" - ) + MENU_ENUM_SUBLABEL_RUN_AHEAD_ENABLED, + "Ejecutar la logica del núcleo uno o mas frames por adelentado, y decidir cuando adelantar basados en las pulsaciones del control, esto puede reducir la latencia de entrada percibida, eliminando el lag interno de la consola o juego emulado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE_STEP, - "Cada vez que aumentes o disminuyas el tamaño del búfer por medio de está interfaz, cambiará esta cantidad" - ) + MENU_ENUM_SUBLABEL_RUN_AHEAD_FRAMES, + "El número de frames que el núcleo irá adelantado, si excedes el número de frames de lag internos del juego, puede causar tirones (jitter)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_IDX, - "Posición en el indice de la lista" - ) + MENU_ENUM_SUBLABEL_RUN_AHEAD_SECONDARY_INSTANCE, + "Usar una segunda instancia del núcleo para adelantarse (RunAhead). Previene problemas de audio causados por las cargas de estado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_ADDRESS_BIT_POSITION, - "Bitmask de la dirección cuando el tamaño de la búsqueda de memoria es menor a 8 bits" - ) + MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS, + "Oculta el mensaje de advertencia que aparece al usar RunAhead si el núcleo no soporta guardar el estado (savestates)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_MATCH_IDX, - "Seleccionar la coincidencia a ver" - ) + MENU_ENUM_SUBLABEL_REWIND_ENABLE, + "Habilita el rebobinado. Tendrá un impacto en el rendimiento del juego" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_START_OR_CONT, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_TOGGLE, + "Aplicar truco inmediatamente después de cambiar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_START_OR_RESTART, - "Izquierda/Derecha para cambiar el bit-size" - ) + MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_LOAD, + "Auto-aplicar los trucos después que el juego cargue" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EXACT, - "Izquierda/Derecha para cambiar el valor" - ) + MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, + "Rebobinar un determinado número de frames a la vez, para aumentar la velocidad del rebobinado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_LT, - "" - ) + MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE, + "La cantidad de memoria (en MB) a reservar para el búfer de rebobinado. Aumentar esto aumentará el largo del historial de rebobinado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_GT, - "" - ) + MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE_STEP, + "Cada vez que aumentes o disminuyas el tamaño del búfer por medio de está interfaz, cambiará esta cantidad" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_LTE, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_IDX, + "Posición en el indice de la lista" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_GTE, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_ADDRESS_BIT_POSITION, + "Bitmask de la dirección cuando el tamaño de la búsqueda de memoria es menor a 8 bits" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQ, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_MATCH_IDX, + "Seleccionar la coincidencia a ver" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_NEQ, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_START_OR_CONT, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQPLUS, - "Izquierda/Derecha para cambiar el valor" - ) + MENU_ENUM_SUBLABEL_CHEAT_START_OR_RESTART, + "Izquierda/Derecha para cambiar el bit-size" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQMINUS, - "Izquierda/Derecha para cambiar el valor" - ) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EXACT, + "Izquierda/Derecha para cambiar el valor" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_ADD_MATCHES, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_LT, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_VIEW_MATCHES, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_GT, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_CREATE_OPTION, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_LTE, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_DELETE_OPTION, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_GTE, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_ADD_NEW_TOP, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQ, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_ADD_NEW_BOTTOM, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_NEQ, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_DELETE_ALL, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQPLUS, + "Izquierda/Derecha para cambiar el valor" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_BIG_ENDIAN, - "Big endian : 258 = 0x0102,\nLittle endian : 258 = 0x0201" - ) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQMINUS, + "Izquierda/Derecha para cambiar el valor" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, - "Nivel de registro para núcleos, si el núcleo emite valores por debajo, serán ignorados" - ) + MENU_ENUM_SUBLABEL_CHEAT_ADD_MATCHES, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PERFCNT_ENABLE, - "Activa los contadores de rendimiento para RetroArch y núcleos" - ) + MENU_ENUM_SUBLABEL_CHEAT_VIEW_MATCHES, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Hacer un guardado rápido al salir de RetroArch. Se cargará automáticamente si 'Cargar guardado rápido automáticamente' esta activado" - ) + MENU_ENUM_SUBLABEL_CHEAT_CREATE_OPTION, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, - "Carga el guardado rápido automático al inicio" - ) + MENU_ENUM_SUBLABEL_CHEAT_DELETE_OPTION, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE, - "Mostrar miniaturas de los guardados rápidos en el menú" - ) + MENU_ENUM_SUBLABEL_CHEAT_ADD_NEW_TOP, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, - "Intervalo en segundos para auto-guardar la memoria no volátil SaveRAM, por defecto desactivado (en 0)" - ) + MENU_ENUM_SUBLABEL_CHEAT_ADD_NEW_BOTTOM, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, - "Al activarlo anula los controles por defecto y usa los controles personalizados para el núcleo actual" - ) + MENU_ENUM_SUBLABEL_CHEAT_DELETE_ALL, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_AUTODETECT_ENABLE, - "Activar la auto-detección de controles, se intentará configurarlos estilo 'Plug and Play'" - ) + MENU_ENUM_SUBLABEL_CHEAT_RELOAD_CHEATS, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_INPUT_SWAP_OK_CANCEL, - "Intercambiar los botones de OK y Cancelar. Desactivado es el estilo Japones, Activado el estilo occidental" - ) + MENU_ENUM_SUBLABEL_CHEAT_BIG_ENDIAN, + "Big endian : 258 = 0x0102,\nLittle endian : 258 = 0x0201" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Al desactivarlo el contenido continuará ejecutándose cuando estés en el menú" - ) + MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, + "Nivel de registro para núcleos, si el núcleo emite valores por debajo, serán ignorados" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_DRIVER, - "Controlador de video a usar" - ) + MENU_ENUM_SUBLABEL_PERFCNT_ENABLE, + "Activa los contadores de rendimiento para RetroArch y núcleos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_DRIVER, - "Controlador de audio a usar" - ) + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, + "Hacer un guardado rápido al salir de RetroArch. Se cargará automáticamente si 'Cargar guardado rápido automáticamente' esta activado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DRIVER, - "Controlador de entrada a usar. El controlador de video puede forzar uno distinto" - ) + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, + "Carga el guardado rápido automático al inicio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, - "Controlador de mando a usar" - ) + MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE, + "Mostrar miniaturas de los guardados rápidos en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_DRIVER, - "Audio resampler a usar" - ) + MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, + "Intervalo en segundos para auto-guardar la memoria no volátil SaveRAM, por defecto desactivado (en 0)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CAMERA_DRIVER, - "Controlador de Cámara a usar" - ) + MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, + "Al activarlo anula los controles por defecto y usa los controles personalizados para el núcleo actual" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LOCATION_DRIVER, - "Controlador de ubicación a usar" - ) + MENU_ENUM_SUBLABEL_INPUT_AUTODETECT_ENABLE, + "Activar la auto-detección de controles, se intentará configurarlos estilo 'Plug and Play'" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_DRIVER, - "Controlador de menú a usar" - ) + MENU_ENUM_SUBLABEL_MENU_INPUT_SWAP_OK_CANCEL, + "Intercambiar los botones de OK y Cancelar. Desactivado es el estilo Japones, Activado el estilo occidental" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RECORD_DRIVER, - "Controlador de grabación a usar" - ) + MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, + "Al desactivarlo el contenido continuará ejecutándose cuando estés en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIDI_DRIVER, - "Controlador MIDI a usar" - ) + MENU_ENUM_SUBLABEL_VIDEO_DRIVER, + "Controlador de video a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_WIFI_DRIVER, - "Controlador WiFi a usar" - ) + MENU_ENUM_SUBLABEL_AUDIO_DRIVER, + "Controlador de audio a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, - "Solo mostrar archivos con extensiones conocidas" - ) + MENU_ENUM_SUBLABEL_INPUT_DRIVER, + "Controlador de entrada a usar. El controlador de video puede forzar uno distinto" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_WALLPAPER, - "Seleccionar una imagen para usar de fondo en el menú" - ) + MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, + "Controlador de mando a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER, - "Cargar una imagen de fondo según el contenido" - ) + MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_DRIVER, + "Audio resampler a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_DEVICE, - "Dispositivo a usar por el controlador de audio. Depende del controlador" - ) + MENU_ENUM_SUBLABEL_CAMERA_DRIVER, + "Controlador de Cámara a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN, - "DSP que procesa el audio antes de ser enviado al controlador" - ) + MENU_ENUM_SUBLABEL_LOCATION_DRIVER, + "Controlador de ubicación a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_OUTPUT_RATE, - "Velocidad de muestreo de la salida de audio" - ) + MENU_ENUM_SUBLABEL_MENU_DRIVER, + "Controlador de menú a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, - "Controla la transparencia de la superposición" - ) + MENU_ENUM_SUBLABEL_RECORD_DRIVER, + "Controlador de grabación a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_OVERLAY_SCALE, - "Controla el tamaño de la superposición" - ) + MENU_ENUM_SUBLABEL_MIDI_DRIVER, + "Controlador MIDI a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ENABLE, - "Activar superposición" - ) + MENU_ENUM_SUBLABEL_WIFI_DRIVER, + "Controlador WiFi a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_OVERLAY_PRESET, - "Seleciona una superposición desde el explorador de archivos" - ) + MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Solo mostrar archivos con extensiones conocidas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, - "La dirección IP del servidor a conectar" - ) + MENU_ENUM_SUBLABEL_MENU_WALLPAPER, + "Seleccionar una imagen para usar de fondo en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT, - "El puerto del servidor a conectar. Puede ser TCP o UDP" - ) + MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER, + "Cargar una imagen de fondo según el contenido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, - "Contraseña a pedir a los clientes que se conecten al estar en modo servidor" - ) + MENU_ENUM_SUBLABEL_AUDIO_DEVICE, + "Dispositivo a usar por el controlador de audio. Depende del controlador" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, - "Permite ser encontrado fácilmente, sino los clientes deberán conectarse manualmente" - ) + MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN, + "DSP que procesa el audio antes de ser enviado al controlador" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, - "Contraseña a pedir a los espectadores que se conecten al estar en modo servidor" - ) + MENU_ENUM_SUBLABEL_AUDIO_OUTPUT_RATE, + "Velocidad de muestreo de la salida de audio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_START_AS_SPECTATOR, - "Si se debe iniciar juego en red en modo espectador" - ) + MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, + "Controla la transparencia de la superposición" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_SLAVES, - "Si se permiten conexiones en modo esclavo. El modo esclavo usa muy poco poder de procesamiento, pero tendrá un impacto significativo en la latencia" - ) + MENU_ENUM_SUBLABEL_OVERLAY_SCALE, + "Controla el tamaño de la superposición" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_REQUIRE_SLAVES, - "Solo usar modo esclavo. No recomendado excepto en redes muy rápidas con máquinas muy débiles" - ) + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ENABLE, + "Activar superposición" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_STATELESS_MODE, - "Necesita una red muy rápida, pero se eliminarán los tirones al no realizar rebobinados de sincronización" - ) + MENU_ENUM_SUBLABEL_OVERLAY_PRESET, + "Seleciona una superposición desde el explorador de archivos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_CHECK_FRAMES, - "Frecuencia en frames con la que se verificará si el servidor y el cliente están en sincronía" - ) + MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, + "La dirección IP del servidor a conectar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_NAT_TRAVERSAL, - "Cuando se es servidor, intentar escuchar conexiones desde Internet, usando UPnP o tecnologías similares" - ) + MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT, + "El puerto del servidor a conectar. Puede ser TCP o UDP" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, - "Activar linea de comandos stdin" - ) + MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, + "Contraseña a pedir a los clientes que se conecten al estar en modo servidor" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MOUSE_ENABLE, - "Activar control con ratón en el menú" - ) + MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, + "Permite ser encontrado fácilmente, sino los clientes deberán conectarse manualmente" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_POINTER_ENABLE, - "Activar controles táctiles en el menú" - ) + MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, + "Contraseña a pedir a los espectadores que se conecten al estar en modo servidor" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_THUMBNAILS, - "Tipo de miniaturas a mostrar" - ) + MENU_ENUM_SUBLABEL_NETPLAY_START_AS_SPECTATOR, + "Si se debe iniciar juego en red en modo espectador" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, - "Tipo de miniaturas a mostrar a la izquierda" - ) + MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_SLAVES, + "Si se permiten conexiones en modo esclavo. El modo esclavo usa muy poco poder de procesamiento, pero tendrá un impacto significativo en la latencia" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_XMB_VERTICAL_THUMBNAILS, - "Muestra la miniatura izquierda debajo de la derecha, a la derecha de la pantalla" - ) + MENU_ENUM_SUBLABEL_NETPLAY_REQUIRE_SLAVES, + "Solo usar modo esclavo. No recomendado excepto en redes muy rápidas con máquinas muy débiles" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE, - "Mostrar el día y hora en el menú" - ) + MENU_ENUM_SUBLABEL_NETPLAY_STATELESS_MODE, + "Necesita una red muy rápida, pero se eliminarán los tirones al no realizar rebobinados de sincronización" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE, - "Mostrar el nivel de batería actual menú" - ) + MENU_ENUM_SUBLABEL_NETPLAY_CHECK_FRAMES, + "Frecuencia en frames con la que se verificará si el servidor y el cliente están en sincronía" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NAVIGATION_WRAPAROUND, - "Volver al principio cuando llegue al final de la lista tanto sea vertical como horizontal" - ) + MENU_ENUM_SUBLABEL_NETPLAY_NAT_TRAVERSAL, + "Cuando se es servidor, intentar escuchar conexiones desde Internet, usando UPnP o tecnologías similares" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, - "Este dispositivo será el anfitrión de la partida" - ) + MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, + "Activar linea de comandos stdin" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_CLIENT, - "Serás un cliente de la partida" - ) + MENU_ENUM_SUBLABEL_MOUSE_ENABLE, + "Activar control con ratón en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_DISCONNECT, - "Desconecta una sesión activa de juego en red" - ) + MENU_ENUM_SUBLABEL_POINTER_ENABLE, + "Activar controles táctiles en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SCAN_DIRECTORY, - "Escanea una carpeta en busca de archivos compatibles y los añade a la colección" - ) + MENU_ENUM_SUBLABEL_THUMBNAILS, + "Tipo de miniaturas a mostrar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SCAN_FILE, - "Escanea un archivo compatible y lo añade a la colección" - ) + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, + "Tipo de miniaturas a mostrar a la izquierda" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SWAP_INTERVAL, - "Un intervalo de 0 significa que la GPU no esperará a intercambiar los búfers, pero puede causar tearing. Un intervalo de 1 significa que la GPU forzará a la CPU a esperar que al menos un cuadro sea mostrado." - ) + MENU_ENUM_SUBLABEL_XMB_VERTICAL_THUMBNAILS, + "Muestra la miniatura izquierda debajo de la derecha, a la derecha de la pantalla" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SORT_SAVEFILES_ENABLE, - "Ordenar archivos de guardado en carpetas nombradas por núcleo" - ) + MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE, + "Mostrar el día y hora en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE, - "Ordenar guardados rápidos en carpetas nombradas por núcleo" - ) + MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE, + "Mostrar el nivel de batería actual menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_REQUEST_DEVICE_I, - "Pedir jugar con el dispositivo de entrada dado" - ) + MENU_ENUM_SUBLABEL_NAVIGATION_WRAPAROUND, + "Volver al principio cuando llegue al final de la lista tanto sea vertical como horizontal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, - "URL de la carpeta del actualizador de núcleos en el buildbot Libretro" - ) + MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, + "Este dispositivo será el anfitrión de la partida" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL, - "URL de la carpeta de recursos en el buildbot Libretro" - ) + MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_CLIENT, + "Serás un cliente de la partida" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, - "Extraer automáticamente los archivos después de descargarlos" - ) + MENU_ENUM_SUBLABEL_NETPLAY_DISCONNECT, + "Desconecta una sesión activa de juego en red" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, - "Escanear en busca de nuevas salas" - ) + MENU_ENUM_SUBLABEL_SCAN_DIRECTORY, + "Escanea una carpeta en busca de archivos compatibles y los añade a la colección" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DELETE_ENTRY, - "Eliminar esta entrada de la colección" - ) + MENU_ENUM_SUBLABEL_SCAN_FILE, + "Escanea un archivo compatible y lo añade a la colección" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INFORMATION, - "Ver mas información sobre el contenido" - ) + MENU_ENUM_SUBLABEL_VIDEO_SWAP_INTERVAL, + "Un intervalo de 0 significa que la GPU no esperará a intercambiar los búfers, pero puede causar tearing. Un intervalo de 1 significa que la GPU forzará a la CPU a esperar que al menos un cuadro sea mostrado." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES, - "Agregar entrada a sus favoritos" - ) + MENU_ENUM_SUBLABEL_SORT_SAVEFILES_ENABLE, + "Ordenar archivos de guardado en carpetas nombradas por núcleo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES_PLAYLIST, - "Agregar entrada a sus favoritos" - ) + MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE, + "Ordenar guardados rápidos en carpetas nombradas por núcleo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RUN, - "Iniciar el contenido" - ) + MENU_ENUM_SUBLABEL_NETPLAY_REQUEST_DEVICE_I, + "Pedir jugar con el dispositivo de entrada dado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, - "Ajuste las opciones del explorador de archivos" - ) + MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, + "URL de la carpeta del actualizador de núcleos en el buildbot Libretro" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, - "Activar controles personalizados por defecto al inicio" - ) + MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL, + "URL de la carpeta de recursos en el buildbot Libretro" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, - "Activar configuración personalizada por defecto al inicio" - ) + MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Extraer automáticamente los archivos después de descargarlos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, - "Activar configuración de núcleos personalizada por defecto al inicio" - ) + MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, + "Escanear en busca de nuevas salas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_ENABLE, - "Muestra el nombre del núcleo actual en el menú" - ) + MENU_ENUM_SUBLABEL_DELETE_ENTRY, + "Eliminar esta entrada de la colección" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DATABASE_MANAGER, - "Ver bases de datos" - ) + MENU_ENUM_SUBLABEL_INFORMATION, + "Ver mas información sobre el contenido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CURSOR_MANAGER, - "Ver búsquedas previas" - ) + MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES, + "Agregar entrada a sus favoritos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, - "Captura una imagen de la pantalla" - ) + MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES_PLAYLIST, + "Agregar entrada a sus favoritos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Cierra el contenido actual. Cualquier cambio no guardado se perderá" - ) + MENU_ENUM_SUBLABEL_RUN, + "Iniciar el contenido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LOAD_STATE, - "Carga un guardado rápido desde la posición seleccionada" - ) + MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, + "Ajuste las opciones del explorador de archivos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVE_STATE, - "Guarda en la posición seleccionada" - ) + MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, + "Activar controles personalizados por defecto al inicio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Reanudar la ejecución del contenido y salir del menú rápido" - ) + MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, + "Activar configuración personalizada por defecto al inicio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Reanudar la ejecución del contenido y salir del menú rápido" - ) + MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, + "Activar configuración de núcleos personalizada por defecto al inicio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_STATE_SLOT, - "Cambia la posición de guardado actual" - ) + MENU_ENUM_SUBLABEL_CORE_ENABLE, + "Muestra el nombre del núcleo actual en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE, - "Si se cargo un guardado, el contenido volverá al estado previo a la carga" - ) + MENU_ENUM_SUBLABEL_DATABASE_MANAGER, + "Ver bases de datos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, - "Si se sobre-escribió un guardado, se volverá al guardado previo" - ) + MENU_ENUM_SUBLABEL_CURSOR_MANAGER, + "Ver búsquedas previas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, - "Servicio de RetroAchievements. Para mas información, visite http://retroachievements.org" - ) + MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, + "Captura una imagen de la pantalla" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, - "Administra las cuentas de usuario" - ) + MENU_ENUM_SUBLABEL_CLOSE_CONTENT, + "Cierra el contenido actual. Cualquier cambio no guardado se perderá" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_REWIND, - "Administra las opciones de rebobinado" - ) + MENU_ENUM_SUBLABEL_LOAD_STATE, + "Carga un guardado rápido desde la posición seleccionada" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_DETAILS, - "Administra los detalles de los trucos" - ) + MENU_ENUM_SUBLABEL_SAVE_STATE, + "Guarda en la posición seleccionada" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_SEARCH, - "Iniciar o continuar una búsqueda de trucos" - ) + MENU_ENUM_SUBLABEL_RESUME, + "Reanudar la ejecución del contenido y salir del menú rápido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RESTART_CONTENT, - "Reinicia el contenido desde el principio" - ) + MENU_ENUM_SUBLABEL_RESUME_CONTENT, + "Reanudar la ejecución del contenido y salir del menú rápido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, - "Guarda un archivo de personalización que se aplicará a todo el contenido cargado con este núcleo. Tomará precedencia sobre la configuración principal" - ) + MENU_ENUM_SUBLABEL_STATE_SLOT, + "Cambia la posición de guardado actual" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, - "Guarda un archivo de configuraciones que aplicará a todo el contenido cargado desde el mismo directorio que el archivo actual. Toma precedencia sobre el archivo principal" - ) + MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE, + "Si se cargo un guardado, el contenido volverá al estado previo a la carga" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, - "Guarda un archivo de personalización que se aplicará solo a este contenido cargado. Tomará precedencia sobre la configuración principal" - ) + MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, + "Si se sobre-escribió un guardado, se volverá al guardado previo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, - "Configurar trucos" - ) + MENU_ENUM_SUBLABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, + "Servicio de RetroAchievements. Para mas información, visite http://retroachievements.org" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SHADER_OPTIONS, - "Configurar shaders para mejorar la imagen" - ) + MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, + "Administra las cuentas de usuario" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Cambia los controles para el contenido cargado actualmente" - ) + MENU_ENUM_SUBLABEL_INPUT_META_REWIND, + "Administra las opciones de rebobinado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Cambia las opciones para el contenido cargado actualmente" - ) + MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_DETAILS, + "Administra los detalles de los trucos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, - "Mostrar opciones avanzadas (ocultas por defecto)" - ) + MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_SEARCH, + "Iniciar o continuar una búsqueda de trucos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, - "Realizar tareas en un hilo separado" - ) + MENU_ENUM_SUBLABEL_RESTART_CONTENT, + "Reinicia el contenido desde el principio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, - "Permitir al usuario eliminar entradas de las colecciones" - ) + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Guarda un archivo de personalización que se aplicará a todo el contenido cargado con este núcleo. Tomará precedencia sobre la configuración principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, - "Establece la carpeta de sistema. Los núcleos usan esto para cargar BIOS, configuraciones de sistema, etc." - ) + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, + "Guarda un archivo de configuraciones que aplicará a todo el contenido cargado desde el mismo directorio que el archivo actual. Toma precedencia sobre el archivo principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, - "Establece la carpeta inicial del explorador de archivos" - ) + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, + "Guarda un archivo de personalización que se aplicará solo a este contenido cargado. Tomará precedencia sobre la configuración principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_DIR, - "Usualmente establecido por desarrolladores que empaquetan aplicaciones libretro/RetroArch para apuntar a los recursos" - ) + MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, + "Configurar trucos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPERS_DIRECTORY, - "Carpeta donde se guardan los fondos de pantalla dinámicos que cambian según el contenido" - ) + MENU_ENUM_SUBLABEL_SHADER_OPTIONS, + "Configurar shaders para mejorar la imagen" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_THUMBNAILS_DIRECTORY, - "Carpeta de miniaturas (cajas, etc.)" - ) + MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, + "Cambia los controles para el contenido cargado actualmente" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, - "Establece la ubicación inicial del explorador del menú" - ) + MENU_ENUM_SUBLABEL_CORE_OPTIONS, + "Cambia las opciones para el contenido cargado actualmente" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, - "El número de frames de entrada a usar para ocultar la latencia de red durante juego en red. Reduce los tirones y el uso de CPU, a costa de incrementar la latencia de entrada" - ) + MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, + "Mostrar opciones avanzadas (ocultas por defecto)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, - "El rango de frames de entrada a usar para ocultar la latencia de red durante juego en red. Reduce los tirones y el uso de CPU, a costa de incrementar la latencia de entrada dentro de un rango" - ) + MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, + "Realizar tareas en un hilo separado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DISK_CYCLE_TRAY_STATUS, - "Continua el ciclo de discos. Si el disco fue introducido, se expulsará sino se introducirá" - ) + MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, + "Permitir al usuario eliminar entradas de las colecciones" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DISK_INDEX, - "Cambiar el indice de disco" - ) + MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, + "Establece la carpeta de sistema. Los núcleos usan esto para cargar BIOS, configuraciones de sistema, etc." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DISK_OPTIONS, - "Administrar imágenes de disco" - ) + MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, + "Establece la carpeta inicial del explorador de archivos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DISK_IMAGE_APPEND, - "Seleccionar una imagen de disco a insertar" - ) + MENU_ENUM_SUBLABEL_CONTENT_DIR, + "Usualmente establecido por desarrolladores que empaquetan aplicaciones libretro/RetroArch para apuntar a los recursos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_ENUM_THROTTLE_FRAMERATE, - "Limita los FPS en el menú" - ) + MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPERS_DIRECTORY, + "Carpeta donde se guardan los fondos de pantalla dinámicos que cambian según el contenido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_XMB_LAYOUT, - "Seleccionar una disposición diferente para la interfaz XMB" - ) + MENU_ENUM_SUBLABEL_THUMBNAILS_DIRECTORY, + "Carpeta de miniaturas (cajas, etc.)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_XMB_THEME, - "Seleccionar un tema de iconos diferente. Los cambios tendrán efecto al reiniciar" - ) + MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, + "Establece la ubicación inicial del explorador del menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE, - "Activar sombra para los iconos. Tendrá un pequeño impacto en el rendimiento" - ) + MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "El número de frames de entrada a usar para ocultar la latencia de red durante juego en red. Reduce los tirones y el uso de CPU, a costa de incrementar la latencia de entrada" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME, - "Seleccionar un color diferente para el menú" - ) + MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "El rango de frames de entrada a usar para ocultar la latencia de red durante juego en red. Reduce los tirones y el uso de CPU, a costa de incrementar la latencia de entrada dentro de un rango" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY, - "Modificar la opacidad de la imagen de fondo" - ) + MENU_ENUM_SUBLABEL_DISK_CYCLE_TRAY_STATUS, + "Continua el ciclo de discos. Si el disco fue introducido, se expulsará sino se introducirá" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_XMB_MENU_COLOR_THEME, - "Seleccionar un color diferente para el menú" - ) + MENU_ENUM_SUBLABEL_DISK_INDEX, + "Cambiar el indice de disco" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, - "Seleccionar un fondo animado. Puede causar problemas de rendimiento dependiendo del efecto, desactivar si el dispositivo no tiene suficiente potencia" - ) + MENU_ENUM_SUBLABEL_DISK_OPTIONS, + "Administrar imágenes de disco" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_XMB_FONT, - "Seleccionar el tipo de letra usado en el menú" - ) + MENU_ENUM_SUBLABEL_DISK_IMAGE_APPEND, + "Seleccionar una imagen de disco a insertar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_FAVORITES, - "Mostrar la pestaña de favoritos en el menú principal" - ) + MENU_ENUM_SUBLABEL_MENU_ENUM_THROTTLE_FRAMERATE, + "Limita los FPS en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, - "Mostrar la pestaña de imágenes en el menú principal" - ) + MENU_ENUM_SUBLABEL_VRR_RUNLOOP_ENABLE, + "No desviarse del los tiempos del núcleo. Usar con pantallas de refresco variable, G-Sync, FreeSync" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, - "Mostrar la pestaña de música en el menú principal" - ) + MENU_ENUM_SUBLABEL_XMB_LAYOUT, + "Seleccionar una disposición diferente para la interfaz XMB" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, - "Mostrar la pestaña de video en el menú principal" - ) + MENU_ENUM_SUBLABEL_XMB_THEME, + "Seleccionar un tema de iconos diferente. Los cambios tendrán efecto al reiniciar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, - "Mostrar la pestaña de juego en red en el menú principal" - ) + MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE, + "Activar sombra para los iconos. Tendrá un pequeño impacto en el rendimiento" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS, - "Mostrar la pestaña de configuración en el menú principal" - ) + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME, + "Seleccionar un color diferente para el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_HISTORY, - "Mostrar la pestaña de historial en el menú principal" - ) + MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY, + "Modificar la opacidad de la imagen de fondo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, - "Mostrar la pestaña de importar contenido en el menú principal" - ) + MENU_ENUM_SUBLABEL_XMB_MENU_COLOR_THEME, + "Seleccionar un color diferente para el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Mostrar las pestañas de playlists en el menú principal" - ) + MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, + "Seleccionar un fondo animado. Puede causar problemas de rendimiento dependiendo del efecto, desactivar si el dispositivo no tiene suficiente potencia" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, - "Mostrar pantalla de inicio. Esto es desactivado automáticamente después del primer inicio" - ) + MENU_ENUM_SUBLABEL_XMB_FONT, + "Seleccionar el tipo de letra usado en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, - "Modificar opacidad del encabezado" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_FAVORITES, + "Mostrar la pestaña de favoritos en el menú principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, - "Modificar opacidad del pie de página" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, + "Mostrar la pestaña de imágenes en el menú principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DPI_OVERRIDE_ENABLE, - "El menú es escalado dinamicamente. Activar si desea un valor predefinido" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, + "Mostrar la pestaña de música en el menú principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DPI_OVERRIDE_VALUE, - "Establecer DPI. NOTA: Debe activar 'Forzar DPI' para que tenga efecto" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, + "Mostrar la pestaña de video en el menú principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, - "Guardar archivos descargados en esta carpeta" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, + "Mostrar la pestaña de juego en red en el menú principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_REMAPPING_DIRECTORY, - "Guardar controles reasignados en esta carpeta" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS, + "Mostrar la pestaña de configuración en el menú principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, - "Buscar contenido/núcleos en esta carpeta" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_HISTORY, + "Mostrar la pestaña de historial en el menú principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LIBRETRO_INFO_PATH, - "Los archivos de información de aplicación y de núcleos se ubican aquí" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, + "Mostrar la pestaña de importar contenido en el menú principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, - "Los archivos de auto-configuración de mandos se guardan aquí" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, + "Mostrar las pestañas de playlists en el menú principal" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PLAYLIST_DIRECTORY, - "Guardar colecciones en esta carpeta" - ) + MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, + "Mostrar pantalla de inicio. Esto es desactivado automáticamente después del primer inicio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, - "Almacenar archivos temporales aquí" - ) + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, + "Modificar opacidad del encabezado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CURSOR_DIRECTORY, - "Almacenar búsquedas guardadas aquí" - ) + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, + "Modificar opacidad del pie de página" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, - "Las bases de datos están aquí" - ) + MENU_ENUM_SUBLABEL_DPI_OVERRIDE_ENABLE, + "El menú es escalado dinamicamente. Activar si desea un valor predefinido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, - "Carpeta de recursos, donde la interfaz buscará los iconos e imágenes" - ) + MENU_ENUM_SUBLABEL_DPI_OVERRIDE_VALUE, + "Establecer DPI. NOTA: Debe activar 'Forzar DPI' para que tenga efecto" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVEFILE_DIRECTORY, - "Carpeta de guardados, si no se establece se guardará en la carpeta del contenido" - ) + MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, + "Guardar archivos descargados en esta carpeta" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_DIRECTORY, - "Carpeta de guardados rápidos, si no se establece se guardará en la carpeta del contenido" - ) + MENU_ENUM_SUBLABEL_INPUT_REMAPPING_DIRECTORY, + "Guardar controles reasignados en esta carpeta" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, - "Carpeta donde guardar capturas de pantalla" - ) + MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, + "Buscar contenido/núcleos en esta carpeta" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_OVERLAY_DIRECTORY, - "Carpeta de donde cargar superposiciones" - ) + MENU_ENUM_SUBLABEL_LIBRETRO_INFO_PATH, + "Los archivos de información de aplicación y de núcleos se ubican aquí" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_DATABASE_PATH, - "Carpeta de donde cargar trucos" - ) + MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, + "Los archivos de auto-configuración de mandos se guardan aquí" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_FILTER_DIR, - "Carpeta de donde cargar filtros DSP" - ) + MENU_ENUM_SUBLABEL_PLAYLIST_DIRECTORY, + "Guardar colecciones en esta carpeta" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FILTER_DIR, - "Carpeta de donde cargar filtros basados en CPU" - ) + MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, + "Almacenar archivos temporales aquí" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_DIR, - "Carpeta de donde cargar filtros basados en GPU" - ) + MENU_ENUM_SUBLABEL_CURSOR_DIRECTORY, + "Almacenar búsquedas guardadas aquí" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RECORDING_OUTPUT_DIRECTORY, - "Carpeta de donde guardar grabaciones" - ) + MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, + "Las bases de datos están aquí" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RECORDING_CONFIG_DIRECTORY, - "Carpeta de donde guardar las configuraciones de grabación" - ) + MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, + "Carpeta de recursos, donde la interfaz buscará los iconos e imágenes" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_PATH, - "Seleccionar un tipo de fuente diferente para las notificaciones" - ) + MENU_ENUM_SUBLABEL_SAVEFILE_DIRECTORY, + "Carpeta de guardados, si no se establece se guardará en la carpeta del contenido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SHADER_APPLY_CHANGES, - "Los cambios en la configuración del shader tomarán efecto inmediatamente. Usalo al cambiar la cantidad de pasadas, filtrado, etc." - ) + MENU_ENUM_SUBLABEL_SAVESTATE_DIRECTORY, + "Carpeta de guardados rápidos, si no se establece se guardará en la carpeta del contenido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_NUM_PASSES, - "Cambiar la cantidad de pasadas de shaders. Puedes asignar shaders individualmente a cada pasada y configurar su escalado y filtrado" - ) + MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, + "Carpeta donde guardar capturas de pantalla" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET, - "Cargar un preset de shader. Sera configurado automáticamente" - ) + MENU_ENUM_SUBLABEL_OVERLAY_DIRECTORY, + "Carpeta de donde cargar superposiciones" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_AS, - "Guardar la configuración actual de shaders cono un nuevo preset" - ) + MENU_ENUM_SUBLABEL_CHEAT_DATABASE_PATH, + "Carpeta de donde cargar trucos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, - "Guardar la configuración actual de shaders para este núcleo" - ) + MENU_ENUM_SUBLABEL_AUDIO_FILTER_DIR, + "Carpeta de donde cargar filtros DSP" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_PARENT, - "Guardar la configuración actual de shaders para todos los archivos en el directorio de contenido actual" - ) + MENU_ENUM_SUBLABEL_VIDEO_FILTER_DIR, + "Carpeta de donde cargar filtros basados en CPU" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, - "Guardar la configuración actual de shaders para este contenido" - ) + MENU_ENUM_SUBLABEL_VIDEO_SHADER_DIR, + "Carpeta de donde cargar filtros basados en GPU" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, - "Modifica el shader directamente. Los cambios no serán guardados en el preset" - ) + MENU_ENUM_SUBLABEL_RECORDING_OUTPUT_DIRECTORY, + "Carpeta de donde guardar grabaciones" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PARAMETERS, - "Modifica el preset de shader actualmente usado en el menú" - ) + MENU_ENUM_SUBLABEL_RECORDING_CONFIG_DIRECTORY, + "Carpeta de donde guardar las configuraciones de grabación" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, - "Cambiar la cantidad de trucos a usar" - ) + MENU_ENUM_SUBLABEL_VIDEO_FONT_PATH, + "Seleccionar un tipo de fuente diferente para las notificaciones" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_APPLY_CHANGES, - "Los cambios en los trucos tendrán efecto inmediatamente" - ) + MENU_ENUM_SUBLABEL_SHADER_APPLY_CHANGES, + "Los cambios en la configuración del shader tomarán efecto inmediatamente. Usalo al cambiar la cantidad de pasadas, filtrado, etc." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_START_SEARCH, - "Inciar búsqueda de un truco nuevo. El número de bits se puede cambiar" - ) + MENU_ENUM_SUBLABEL_VIDEO_SHADER_NUM_PASSES, + "Cambiar la cantidad de pasadas de shaders. Puedes asignar shaders individualmente a cada pasada y configurar su escalado y filtrado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_CONTINUE_SEARCH, - "Continuar búsqueda de un truco nuevo" - ) + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET, + "Cargar un preset de shader. Sera configurado automáticamente" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, - "Cargar archivo de trucos reemplazando los existentes" - ) + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_AS, + "Guardar la configuración actual de shaders cono un nuevo preset" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD_APPEND, - "Cargar archivo de trucos agregandolos a los existentes" - ) + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, + "Guardar la configuración actual de shaders para este núcleo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_FILE_SAVE_AS, - "Guardar trucos actuales a un archivo" - ) + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_PARENT, + "Guardar la configuración actual de shaders para todos los archivos en el directorio de contenido actual" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SETTINGS, - "Accede rápidamente a todas las opciones del juego" - ) + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, + "Guardar la configuración actual de shaders para este contenido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFORMATION, - "Ver información pertinente a la aplicación/núcleo" - ) + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, + "Modifica el shader directamente. Los cambios no serán guardados en el preset" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO, - "Valor de punto flotante (ancho / alto), usado si la relación de aspecto es 'Personal'" - ) + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PARAMETERS, + "Modifica el preset de shader actualmente usado en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "Alto usada si la relación de aspecto es establecida en 'Personal'" - ) + MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, + "Cambiar la cantidad de trucos a usar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "Ancho usada si la relación de aspecto es establecida en 'Personal'" - ) + MENU_ENUM_SUBLABEL_CHEAT_APPLY_CHANGES, + "Los cambios en los trucos tendrán efecto inmediatamente" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, - "Margen de posición sobre el eje X de la pantalla. Serán ignorados si 'Escalar en múltiplos enteros' es activado, Entonces serán centrados" - ) + MENU_ENUM_SUBLABEL_CHEAT_START_SEARCH, + "Inciar búsqueda de un truco nuevo. El número de bits se puede cambiar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, - "Margen de posición sobre el eje Y de la pantalla. Serán ignorados si 'Escalar en múltiplos enteros' es activado, Entonces serán centrados" - ) + MENU_ENUM_SUBLABEL_CHEAT_CONTINUE_SEARCH, + "Continuar búsqueda de un truco nuevo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Usar servidor relé" - ) + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, + "Cargar archivo de trucos reemplazando los existentes" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, - "Enviar conexiones de juego en red a través de otro servidor (man-in-the-middle). Útil si el servidor está detrás de un firewall o tiene problemas NAT/UPnP" - ) + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD_APPEND, + "Cargar archivo de trucos agregandolos a los existentes" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER, - "Ubicación del servidor relé" - ) + MENU_ENUM_SUBLABEL_CHEAT_FILE_SAVE_AS, + "Guardar trucos actuales a un archivo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_MITM_SERVER, - "Elegir un servidor relé especifico. Las ubicaciones geográficamente cercanas tienden a tener menor latencia" - ) + MENU_ENUM_SUBLABEL_CONTENT_SETTINGS, + "Accede rápidamente a todas las opciones del juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, - "Agregar al mezclador" - ) + MENU_ENUM_SUBLABEL_CORE_INFORMATION, + "Ver información pertinente a la aplicación/núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_PLAY, - "Add to mixer and play" - ) + MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO, + "Valor de punto flotante (ancho / alto), usado si la relación de aspecto es 'Personal'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION, - "Agregar al mezclador y colección" - ) + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, + "Alto usada si la relación de aspecto es establecida en 'Personal'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY, - "Agregar al mezclador y reproducir" - ) + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, + "Ancho usada si la relación de aspecto es establecida en 'Personal'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, - "Filtrar por núcleo actual" - ) + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, + "Margen de posición sobre el eje X de la pantalla. Serán ignorados si 'Escalar en múltiplos enteros' es activado, Entonces serán centrados" + ) MSG_HASH( - MSG_AUDIO_MIXER_VOLUME, - "Volumen del mezclador de audio global" - ) + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, + "Margen de posición sobre el eje Y de la pantalla. Serán ignorados si 'Escalar en múltiplos enteros' es activado, Entonces serán centrados" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, - "Volumen global. 0 dB es normal, donde no se aplica ganancia" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, + "Usar servidor relé" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, - "Volumen del mezclador de audio (dB)" - ) + MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, + "Enviar conexiones de juego en red a través de otro servidor (man-in-the-middle). Útil si el servidor está detrás de un firewall o tiene problemas NAT/UPnP" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, - "Silenciar mezclador de audio" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER, + "Ubicación del servidor relé" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, - "Silencia el mezclador de audio" - ) + MENU_ENUM_SUBLABEL_NETPLAY_MITM_SERVER, + "Elegir un servidor relé especifico. Las ubicaciones geográficamente cercanas tienden a tener menor latencia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SHOW_ONLINE_UPDATER, - "Mostrar actualizador en linea" - ) + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, + "Agregar al mezclador" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, - "Mostrar/ocultar la opción de 'Actualizador en línea'" - ) + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_PLAY, + "Add to mixer and play" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_VIEWS_SETTINGS, - "Vistas" - ) + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION, + "Agregar al mezclador y colección" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_VIEWS_SETTINGS, - "Mostrar/ocultar elementos del menú" - ) + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY, + "Agregar al mezclador y reproducir" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, - "Mostrar 'Actualizador de núcleos'" - ) + MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "Filtrar por núcleo actual" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, - "Mostrar/ocultar la habilidad de actualizar núcleos y archivos asociados" - ) + MSG_AUDIO_MIXER_VOLUME, + "Volumen del mezclador de audio global" + ) MSG_HASH( - MSG_PREPARING_FOR_CONTENT_SCAN, - "Preparando para escaneo de contenido..." - ) + MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, + "Volumen global. 0 dB es normal, donde no se aplica ganancia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_DELETE, - "Borrar núcleo" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, + "Volumen del mezclador de audio (dB)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_DELETE, - "Eliminar este núcleo del disco" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, + "Silenciar mezclador de audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, - "Opacidad del Framebuffer" - ) + MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, + "Silencia el mezclador de audio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, - "Modifica la opacidad del framebuffer" - ) + MENU_ENUM_LABEL_VALUE_MENU_SHOW_ONLINE_UPDATER, + "Mostrar actualizador en linea" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, - "Favoritos" - ) + MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, + "Mostrar/ocultar la opción de 'Actualizador en línea'" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_GOTO_FAVORITES, - "Contenido agregado a 'Favoritos' aparecerá aquí" - ) + MENU_ENUM_LABEL_VALUE_MENU_VIEWS_SETTINGS, + "Vistas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, - "Música" - ) + MENU_ENUM_SUBLABEL_MENU_VIEWS_SETTINGS, + "Mostrar/ocultar elementos del menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_GOTO_MUSIC, - "Música que ha sido previamente reproducida aparecerá aquí" - ) + MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, + "Mostrar 'Actualizador de núcleos'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, - "Imagen" - ) + MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, + "Mostrar/ocultar la habilidad de actualizar núcleos y archivos asociados" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_GOTO_IMAGES, - "Imágenes previamente vistas aparecerán aquí" - ) + MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparando para escaneo de contenido..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, - "Video" - ) + MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Borrar núcleo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_GOTO_VIDEO, - "Videos previamente reproducidos aparecerán aquí" - ) + MENU_ENUM_SUBLABEL_CORE_DELETE, + "Eliminar este núcleo del disco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, - "Iconos en el menú" - ) + MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Opacidad del Framebuffer" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, - "Activar/Desactivar los iconos mostrados a la izquierda del menú" - ) + MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modifica la opacidad del framebuffer" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_XMB_MAIN_MENU_ENABLE_SETTINGS, - "Activar pestaña de opciones" - ) + MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favoritos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS_PASSWORD, - "Establecer contraseña para activar la pestaña de opciones" - ) + MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Contenido agregado a 'Favoritos' aparecerá aquí" + ) MSG_HASH( - MSG_INPUT_ENABLE_SETTINGS_PASSWORD, - "Introducir contraseña" - ) + MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Música" + ) MSG_HASH( - MSG_INPUT_ENABLE_SETTINGS_PASSWORD_OK, - "Contraseña correcta" - ) + MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Música que ha sido previamente reproducida aparecerá aquí" + ) MSG_HASH( - MSG_INPUT_ENABLE_SETTINGS_PASSWORD_NOK, - "Contraseña incorrecta" - ) + MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Imagen" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_XMB_MAIN_MENU_ENABLE_SETTINGS, - "Activa la pestaña de opciones. Es necesario reiniciar para que aparezca" - ) + MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Imágenes previamente vistas aparecerán aquí" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS_PASSWORD, - "Proveer una contraseña al ocultar la pestaña de opciones, hace posible restaurarla desde el menú principal, activando 'Mostrar pestaña de opciones'" - ) + MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, - "Permitir al usuario renombrar entradas en colecciones" - ) + MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos previamente reproducidos aparecerán aquí" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, - "Permitir renombrar entradas" - ) + MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Iconos en el menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RENAME_ENTRY, - "Renombrar el título de esta entrada" - ) + MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Activar/Desactivar los iconos mostrados a la izquierda del menú" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RENAME_ENTRY, - "Renombrar" - ) + MENU_ENUM_LABEL_VALUE_XMB_MAIN_MENU_ENABLE_SETTINGS, + "Activar pestaña de opciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CORE, - "Mostrar cargar núcleo" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS_PASSWORD, + "Establecer contraseña para activar la pestaña de opciones" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CORE, - "Mostrar/ocultar la opción de 'Cargar núcleo'" - ) + MSG_INPUT_ENABLE_SETTINGS_PASSWORD, + "Introducir contraseña" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CONTENT, - "Mostrar cargar contenido" - ) + MSG_INPUT_ENABLE_SETTINGS_PASSWORD_OK, + "Contraseña correcta" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CONTENT, - "Mostrar/ocultar la opción de 'Cargar contenido'" - ) + MSG_INPUT_ENABLE_SETTINGS_PASSWORD_NOK, + "Contraseña incorrecta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SHOW_INFORMATION, - "Mostrar Información" - ) + MENU_ENUM_SUBLABEL_XMB_MAIN_MENU_ENABLE_SETTINGS, + "Activa la pestaña de opciones. Es necesario reiniciar para que aparezca" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SHOW_INFORMATION, - "Mostrar/ocultar la opción de 'Información'" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS_PASSWORD, + "Proveer una contraseña al ocultar la pestaña de opciones, hace posible restaurarla desde el menú principal, activando 'Mostrar pestaña de opciones'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SHOW_CONFIGURATIONS, - "Mostrar configuraciones" - ) + MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, + "Permitir al usuario renombrar entradas en colecciones" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SHOW_CONFIGURATIONS, - "Mostrar/ocultar la opción de 'Configuraciones'" - ) + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Permitir renombrar entradas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SHOW_HELP, - "Mostrar ayuda" - ) + MENU_ENUM_SUBLABEL_RENAME_ENTRY, + "Renombrar el título de esta entrada" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SHOW_HELP, - "Mostrar/ocultar la opción de 'Ayuda'" - ) + MENU_ENUM_LABEL_VALUE_RENAME_ENTRY, + "Renombrar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SHOW_QUIT_RETROARCH, - "Mostrar salir de RetroArch" - ) + MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CORE, + "Mostrar cargar núcleo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SHOW_QUIT_RETROARCH, - "Mostrar/ocultar la opción de 'Salir de RetroArch'" - ) + MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CORE, + "Mostrar/ocultar la opción de 'Cargar núcleo'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SHOW_REBOOT, - "Mostrar reiniciar" - ) + MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CONTENT, + "Mostrar cargar contenido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SHOW_REBOOT, - "Mostrar/ocultar la opción de 'Reiniciar'" - ) + MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CONTENT, + "Mostrar/ocultar la opción de 'Cargar contenido'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_SHOW_SHUTDOWN, - "Show Shutdown" - ) + MENU_ENUM_LABEL_VALUE_MENU_SHOW_INFORMATION, + "Mostrar Información" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SHOW_SHUTDOWN, - "Mostrar/ocultar la opción de 'Apagado'" - ) + MENU_ENUM_SUBLABEL_MENU_SHOW_INFORMATION, + "Mostrar/ocultar la opción de 'Información'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_VIEWS_SETTINGS, - "Menú rápido" - ) + MENU_ENUM_LABEL_VALUE_MENU_SHOW_CONFIGURATIONS, + "Mostrar configuraciones" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_VIEWS_SETTINGS, - "Mostrar/ocultar elementos del menú rápido" - ) + MENU_ENUM_SUBLABEL_MENU_SHOW_CONFIGURATIONS, + "Mostrar/ocultar la opción de 'Configuraciones'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_TAKE_SCREENSHOT, - "Mostrar captura de pantalla" - ) + MENU_ENUM_LABEL_VALUE_MENU_SHOW_HELP, + "Mostrar ayuda" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_TAKE_SCREENSHOT, - "Mostrar/ocultar la opción de 'Captura de pantalla'" - ) + MENU_ENUM_SUBLABEL_MENU_SHOW_HELP, + "Mostrar/ocultar la opción de 'Ayuda'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_LOAD_STATE, - "Mostrar guardado rápido" - ) + MENU_ENUM_LABEL_VALUE_MENU_SHOW_QUIT_RETROARCH, + "Mostrar salir de RetroArch" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, - "Mostrar/ocultar la opción de 'Guardado rápido'" - ) + MENU_ENUM_SUBLABEL_MENU_SHOW_QUIT_RETROARCH, + "Mostrar/ocultar la opción de 'Salir de RetroArch'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, - "Mostrar deshacer carga y guardado rápido" - ) + MENU_ENUM_LABEL_VALUE_MENU_SHOW_REBOOT, + "Mostrar reiniciar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, - "Mostrar/ocultar la opción para deshacer la carga y guardado rápido" - ) + MENU_ENUM_SUBLABEL_MENU_SHOW_REBOOT, + "Mostrar/ocultar la opción de 'Reiniciar'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_FAVORITES, - "Mostrar agregar a favoritos" - ) + MENU_ENUM_LABEL_VALUE_MENU_SHOW_SHUTDOWN, + "Show Shutdown" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, - "Mostrar/ocultar la opción de 'Agregar a favoritos'" - ) + MENU_ENUM_SUBLABEL_MENU_SHOW_SHUTDOWN, + "Mostrar/ocultar la opción de 'Apagado'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_OPTIONS, - "Mostrar opciones" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_VIEWS_SETTINGS, + "Menú rápido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_OPTIONS, - "Mostrar/ocultar la opción de 'Opciones'" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_VIEWS_SETTINGS, + "Mostrar/ocultar elementos del menú rápido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CONTROLS, - "Mostrar Controles" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_TAKE_SCREENSHOT, + "Mostrar captura de pantalla" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CONTROLS, - "Mostrar/ocultar la opción de 'Controles'" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_TAKE_SCREENSHOT, + "Mostrar/ocultar la opción de 'Captura de pantalla'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CHEATS, - "Mostrar trucos" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_LOAD_STATE, + "Mostrar guardado rápido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CHEATS, - "Mostrar/ocultar la opción de 'Trucos'" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, + "Mostrar/ocultar la opción de 'Guardado rápido'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SHADERS, - "Mostrar Shaders" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, + "Mostrar deshacer carga y guardado rápido" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SHADERS, - "Mostrar/ocultar la opción de 'Shaders'" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, + "Mostrar/ocultar la opción para deshacer la carga y guardado rápido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, - "Mostrar personalizaciones de núcleo" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_FAVORITES, + "Mostrar agregar a favoritos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, - "Mostrar/ocultar la opción de 'Guardar personalizaciones de núcleo'" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, + "Mostrar/ocultar la opción de 'Agregar a favoritos'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, - "Mostrar personalizaciones de juego" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_OPTIONS, + "Mostrar opciones" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, - "Mostrar/ocultar la opción de 'Guardar personalizaciones de juego'" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_OPTIONS, + "Mostrar/ocultar la opción de 'Opciones'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_INFORMATION, - "Mostrar información" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CONTROLS, + "Mostrar Controles" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_INFORMATION, - "Muestra/oculta la opción de 'Información'" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CONTROLS, + "Mostrar/ocultar la opción de 'Controles'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_ENABLE, - "Activar fondo de notificaciones" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CHEATS, + "Mostrar trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_RED, - "Fondo de notif. componente roja" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CHEATS, + "Mostrar/ocultar la opción de 'Trucos'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_GREEN, - "Fondo de notif. componente verde" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SHADERS, + "Mostrar Shaders" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_BLUE, - "Fondo de notif. componente azul" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SHADERS, + "Mostrar/ocultar la opción de 'Shaders'" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_OPACITY, - "Fondo de notif. opacidad" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, + "Mostrar personalizaciones de núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_DISABLE_KIOSK_MODE, - "Desactivar modo kiosco" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, + "Mostrar/ocultar la opción de 'Guardar personalizaciones de núcleo'" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_DISABLE_KIOSK_MODE, - "Desactiva el modo kiosco. Es necesario reiniciar para completar" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, + "Mostrar personalizaciones de juego" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_ENABLE_KIOSK_MODE, - "Activar modo kiosco" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, + "Mostrar/ocultar la opción de 'Guardar personalizaciones de juego'" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_ENABLE_KIOSK_MODE, - "Protege la configuración ocultándola" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_INFORMATION, + "Mostrar información" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_KIOSK_MODE_PASSWORD, - "Establecer contraseña para desactivar modo kiosco" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_INFORMATION, + "Muestra/oculta la opción de 'Información'" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_KIOSK_MODE_PASSWORD, - "Proveer una contraseña al activar el modo kiosco hace posible desactivarlo desde el menú principal, seleccionando 'Desactivar modo kiosco' e introduciendo la contraseña" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_ENABLE, + "Activar fondo de notificaciones" + ) MSG_HASH( - MSG_INPUT_KIOSK_MODE_PASSWORD, - "Ingresar contraseña" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_RED, + "Fondo de notif. componente roja" + ) MSG_HASH( - MSG_INPUT_KIOSK_MODE_PASSWORD_OK, - "Contraseña correcta" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_GREEN, + "Fondo de notif. componente verde" + ) MSG_HASH( - MSG_INPUT_KIOSK_MODE_PASSWORD_NOK, - "Contraseña incorrecta" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_BLUE, + "Fondo de notif. componente azul" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_RED, - "Notificación componente roja" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_OPACITY, + "Fondo de notif. opacidad" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_GREEN, - "Notificación componente verde" - ) + MENU_ENUM_LABEL_VALUE_MENU_DISABLE_KIOSK_MODE, + "Desactivar modo kiosco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_BLUE, - "Notificación componente azul" - ) + MENU_ENUM_SUBLABEL_MENU_DISABLE_KIOSK_MODE, + "Desactiva el modo kiosco. Es necesario reiniciar para completar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FRAMECOUNT_SHOW, - "Contador de frames junto a FPS" - ) + MENU_ENUM_LABEL_VALUE_MENU_ENABLE_KIOSK_MODE, + "Activar modo kiosco" + ) MSG_HASH( - MSG_CONFIG_OVERRIDE_LOADED, - "Personalizar configuraciones cargadas" - ) + MENU_ENUM_SUBLABEL_MENU_ENABLE_KIOSK_MODE, + "Protege la configuración ocultándola" + ) MSG_HASH( - MSG_GAME_REMAP_FILE_LOADED, - "Archivo de reasignaciones de juego cargado" - ) + MENU_ENUM_LABEL_VALUE_MENU_KIOSK_MODE_PASSWORD, + "Establecer contraseña para desactivar modo kiosco" + ) MSG_HASH( - MSG_CORE_REMAP_FILE_LOADED, - "Archivo de reasignaciones de núcleo cargado" - ) + MENU_ENUM_SUBLABEL_MENU_KIOSK_MODE_PASSWORD, + "Proveer una contraseña al activar el modo kiosco hace posible desactivarlo desde el menú principal, seleccionando 'Desactivar modo kiosco' e introduciendo la contraseña" + ) MSG_HASH( - MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "RunAhead se desactivó porque este núcleo no soporta archivos de estado (savestates)" - ) + MSG_INPUT_KIOSK_MODE_PASSWORD, + "Ingresar contraseña" + ) MSG_HASH( - MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, - "Fallo al guardar el estado. RunAhead se ha desactivado" - ) + MSG_INPUT_KIOSK_MODE_PASSWORD_OK, + "Contraseña correcta" + ) MSG_HASH( - MSG_RUNAHEAD_FAILED_TO_LOAD_STATE, - "Fallo al cargar el estado. RunAhead se ha desactivado" - ) + MSG_INPUT_KIOSK_MODE_PASSWORD_NOK, + "Contraseña incorrecta" + ) MSG_HASH( - MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE, - "Fallo al crear la segunda instancia. RunAhead usará solo una" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_RED, + "Notificación componente roja" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, - "Agregar contenido automáticamente a la lista de reproducción" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_GREEN, + "Notificación componente verde" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, - "Escanea automáticamente el contenido cargado para que aparezca en las listas de reproducción" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_BLUE, + "Notificación componente azul" + ) MSG_HASH( - MSG_SCANNING_OF_FILE_FINISHED, - "Escaneo de archivo finalizado" - ) + MENU_ENUM_LABEL_VALUE_FRAMECOUNT_SHOW, + "Contador de frames junto a FPS" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_OPACITY, - "Opacidad de la ventana" - ) + MSG_CONFIG_OVERRIDE_LOADED, + "Personalizar configuraciones cargadas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_QUALITY, - "Calidad del muestreo de audio" - ) + MSG_GAME_REMAP_FILE_LOADED, + "Archivo de reasignaciones de juego cargado" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_QUALITY, - "Valores mas bajos favorecen el rendimiento y bajan la latencia a costa de la calidad, incrementar el valor aumentará la calidad a costa del rendimiento y latencia" - ) + MSG_CORE_REMAP_FILE_LOADED, + "Archivo de reasignaciones de núcleo cargado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHADER_WATCH_FOR_CHANGES, - "Vigilar cambios en los shader" - ) + MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, + "RunAhead se desactivó porque este núcleo no soporta archivos de estado (savestates)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, - "Auto-aplica los cambios hechos a los archivos shader del disco" - ) + MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, + "Fallo al guardar el estado. RunAhead se ha desactivado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SHOW_DECORATIONS, - "Mostrar Decoraciones de Ventanas" - ) + MSG_RUNAHEAD_FAILED_TO_LOAD_STATE, + "Fallo al cargar el estado. RunAhead se ha desactivado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_STATISTICS_SHOW, - "Mostrar Estadísticas" - ) + MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE, + "Fallo al crear la segunda instancia. RunAhead usará solo una" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_STATISTICS_SHOW, - "Mostrar estadísticas técnicas en pantalla" - ) + MENU_ENUM_LABEL_VALUE_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, + "Agregar contenido automáticamente a la lista de reproducción" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_ENABLE, - "Activar relleno de borde" - ) + MENU_ENUM_SUBLABEL_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, + "Escanea automáticamente el contenido cargado para que aparezca en las listas de reproducción" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, - "Activar ancho del relleno de borde" - ) + MSG_SCANNING_OF_FILE_FINISHED, + "Escaneo de archivo finalizado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, - "Activar ancho del relleno de fondo" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_OPACITY, + "Opacidad de la ventana" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, - "Para pantallas CRT de 15 kHz. Intenta usar la resolución y refresco exactos del núcleo/juego" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_QUALITY, + "Calidad del muestreo de audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, - "CRT SwitchRes" - ) + MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_QUALITY, + "Valores mas bajos favorecen el rendimiento y bajan la latencia a costa de la calidad, incrementar el valor aumentará la calidad a costa del rendimiento y latencia" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, - "Al activar CRT SwitchRes, forzar resolución ultrawide horizontal para minimizar el cambio de modos" - ) + MENU_ENUM_LABEL_VALUE_SHADER_WATCH_FOR_CHANGES, + "Vigilar cambios en los shader" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, - "Super Resolucion CRT" - ) + MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, + "Auto-aplica los cambios hechos a los archivos shader del disco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, - "Mostrar opciones de rebobinado" - ) + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SHOW_DECORATIONS, + "Mostrar Decoraciones de Ventanas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, - "Muestra/oculta las opciones de rebobinado" - ) + MENU_ENUM_LABEL_VALUE_STATISTICS_SHOW, + "Mostrar Estadísticas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_LATENCY, - "Muestra/oculta las opciones de latencia" - ) + MENU_ENUM_SUBLABEL_STATISTICS_SHOW, + "Mostrar estadísticas técnicas en pantalla" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_LATENCY, - "Mostrar opciones de latencia" - ) + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_ENABLE, + "Activar relleno de borde" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_OVERLAYS, - "Muestra/oculta las opciones de superposición" - ) + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, + "Activar ancho del relleno de borde" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_OVERLAYS, - "Mostrar opciones de superposición" - ) + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, + "Activar ancho del relleno de fondo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE_MENU, - "Activar el menu de audio" - ) + MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, + "Para pantallas CRT de 15 kHz. Intenta usar la resolución y refresco exactos del núcleo/juego" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_ENABLE_MENU, - "Activa o desactiva el menu de sonido" - ) + MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, + "CRT SwitchRes" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_SETTINGS, - "Opciones del mezclador" - ) + MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, + "Al activar CRT SwitchRes, forzar resolución ultrawide horizontal para minimizar el cambio de modos" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_MIXER_SETTINGS, - "Ver o modificar las opciones del mezclador de audio" - ) + MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, + "Super Resolucion CRT" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_INFO, - "Info" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, + "Mostrar opciones de rebobinado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_FILE, - "&Archivo" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, + "Muestra/oculta las opciones de rebobinado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_LOAD_CORE, - "&Cargar núcleo..." - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_LATENCY, + "Muestra/oculta las opciones de latencia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_UNLOAD_CORE, - "&Descargar núcleo" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_LATENCY, + "Mostrar opciones de latencia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_EXIT, - "&Salir" - ) + MENU_ENUM_SUBLABEL_CONTENT_SHOW_OVERLAYS, + "Muestra/oculta las opciones de superposición" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT, - "&Editar" - ) + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_OVERLAYS, + "Mostrar opciones de superposición" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT_SEARCH, - "&Buscar" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE_MENU, + "Activar el menu de audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW, - "&Ver" - ) + MENU_ENUM_SUBLABEL_AUDIO_ENABLE_MENU, + "Activa o desactiva el menu de sonido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_CLOSED_DOCKS, - "Docks cerrados" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_SETTINGS, + "Opciones del mezclador" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS, - "&Opciones..." - ) + MENU_ENUM_SUBLABEL_AUDIO_MIXER_SETTINGS, + "Ver o modificar las opciones del mezclador de audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS, - "Recordar las posiciones de dock:" - ) + MENU_ENUM_LABEL_VALUE_QT_INFO, + "Info" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY, - "Recordar la geometría de la ventana:" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE, + "&Archivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB, - "Recordar la ultima pestaña de contenido:" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_LOAD_CORE, + "&Cargar núcleo..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME, - "Tema" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_UNLOAD_CORE, + "&Descargar núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT, - "" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_EXIT, + "&Salir" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK, - "Oscuro" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT, + "&Editar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM, - "Personalizado..." - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT_SEARCH, + "&Buscar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE, - "Opciones" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW, + "&Ver" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_LOAD_CUSTOM_CORE, - "Cargar nucleo personalizado..." - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_CLOSED_DOCKS, + "Docks cerrados" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_LOAD_CORE, - "Cargar núcleo" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_SHADER_PARAMS, + "Parámetros de Shader" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_LOADING_CORE, - "Cargando núcleo..." - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS, + "&Opciones..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_NAME, - "Nombre" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS, + "Recordar las posiciones de dock:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_CORE_VERSION, - "Versión" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY, + "Recordar la geometría de la ventana:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_TAB_PLAYLISTS, - "Playlists" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB, + "Recordar la ultima pestaña de contenido:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER, - "Explorador de archivos" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME, + "Tema" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_TOP, - "Inicio" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT, + "" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_UP, - "Arriba" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK, + "Oscuro" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER, - "Explorador de contenido" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM, + "Personalizado..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_BOXART, - "Caja" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE, + "Opciones" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_SCREENSHOT, - "Captura de pantalla" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_TOOLS, + "Herramien&tas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, - "Pantalla de título" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP, + "A&yuda" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, - "Todas las Playlists" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT, + "Acerca de RetroArch" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_CORE, - "Núcleo" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_DOCUMENTATION, + "Documentación" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_CORE_INFO, - "Info de núcleo" - ) + MENU_ENUM_LABEL_VALUE_QT_LOAD_CUSTOM_CORE, + "Cargar nucleo personalizado..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_CORE_SELECTION_ASK, - "" - ) + MENU_ENUM_LABEL_VALUE_QT_LOAD_CORE, + "Cargar núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_INFORMATION, - "Información" - ) + MENU_ENUM_LABEL_VALUE_QT_LOADING_CORE, + "Cargando núcleo..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_WARNING, - "Advertencia" - ) + MENU_ENUM_LABEL_VALUE_QT_NAME, + "Nombre" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_ERROR, - "Error" - ) + MENU_ENUM_LABEL_VALUE_QT_CORE_VERSION, + "Versión" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_RESTART_TO_TAKE_EFFECT, - "Por favor reinicie el programa para que los cambios tengan efecto" - ) + MENU_ENUM_LABEL_VALUE_QT_TAB_PLAYLISTS, + "Playlists" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_LOG, - "Log" - ) + MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER, + "Explorador de archivos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_TOP, + "Inicio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_UP, + "Arriba" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER, + "Explorador de contenido" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_BOXART, + "Caja" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_SCREENSHOT, + "Captura de pantalla" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, + "Pantalla de título" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, + "Todas las Playlists" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE, + "Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE_INFO, + "Info de núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE_SELECTION_ASK, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_INFORMATION, + "Información" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_WARNING, + "Advertencia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ERROR, + "Error" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR, + "Error de red" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESTART_TO_TAKE_EFFECT, + "Por favor reinicie el programa para que los cambios tengan efecto" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOG, + "Log" + ) #ifdef HAVE_QT MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, - "Escaneo Terminado.

    \n" - "En orden para que el contenido sea correctamente escaneado, debes:\n" - "
    • tener un núcleo compatible descargado
    • \n" - "
    • tener los \"Archivos de información de núcleos\" actualizados
    • \n" - "
    • tener las \"Bases de datos\" actualizadas
    • \n" - "
    • reiniciar RetroArch si actualizaste algo con el \"Actualizador en línea\"
    \n" - "Por último, el contenido debe coincidir las bases de datos existente de
    aquí. Si aún no funciona, considere enviar un reporte de error." - ) + MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, + "Escaneo Terminado.

    \n" + "En orden para que el contenido sea correctamente escaneado, debes:\n" + "
    • tener un núcleo compatible descargado
    • \n" + "
    • tener los \"Archivos de información de núcleos\" actualizados
    • \n" + "
    • tener las \"Bases de datos\" actualizadas
    • \n" + "
    • reiniciar RetroArch si actualizaste algo con el \"Actualizador en línea\"
    \n" + "Por último, el contenido debe coincidir las bases de datos existente de aquí. Si aún no funciona, considere enviar un reporte de error." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHOW_WIMP, - "Mostrar el menú de escritorio" - ) + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + "Mostrar el menú de escritorio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SHOW_WIMP, - "Abre el menú de escritorio si fue cerrado" - ) + MENU_ENUM_SUBLABEL_SHOW_WIMP, + "Abre el menú de escritorio si fue cerrado" + ) #endif MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, - "No mostrar esto de nuevo" - ) + MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, + "No mostrar esto de nuevo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_STOP, - "Detener" - ) + MENU_ENUM_LABEL_VALUE_QT_STOP, + "Detener" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_ASSOCIATE_CORE, - "Asociar núcleo" - ) + MENU_ENUM_LABEL_VALUE_QT_ASSOCIATE_CORE, + "Asociar núcleo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS, - "Playlists Ocultas" - ) + MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS, + "Playlists Ocultas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_HIDE, - "Ocultar" - ) + MENU_ENUM_LABEL_VALUE_QT_HIDE, + "Ocultar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR, - "Color de resaltado" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR, + "Color de resaltado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_CHOOSE, - "&Elegir..." - ) + MENU_ENUM_LABEL_VALUE_QT_CHOOSE, + "&Elegir..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_SELECT_COLOR, - "Seleccionar Color" - ) + MENU_ENUM_LABEL_VALUE_QT_SELECT_COLOR, + "Seleccionar Color" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_SELECT_THEME, - "Seleccionar tema" - ) + MENU_ENUM_LABEL_VALUE_QT_SELECT_THEME, + "Seleccionar tema" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_CUSTOM_THEME, - "Tema personalizado" - ) + MENU_ENUM_LABEL_VALUE_QT_CUSTOM_THEME, + "Tema personalizado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_FILE_PATH_IS_BLANK, - "La dirección está vacía" - ) + MENU_ENUM_LABEL_VALUE_QT_FILE_PATH_IS_BLANK, + "La dirección está vacía" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_FILE_IS_EMPTY, - "Archivo vacío" - ) + MENU_ENUM_LABEL_VALUE_QT_FILE_IS_EMPTY, + "Archivo vacío" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED, - "No se pudo abrir el archivo para la lectura" - ) + MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED, + "No se pudo abrir el archivo para la lectura" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST, - "El archivo no existe" - ) + MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED, + "No se pudo abrir el archivo para escribirlo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST, - "Sugerir el núcleo cargado primero" - ) + MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST, + "El archivo no existe" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_ZOOM, - "Zoom" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST, + "Sugerir el núcleo cargado primero" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_VIEW, - "Vista" - ) + MENU_ENUM_LABEL_VALUE_QT_ZOOM, + "Zoom" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_ICONS, - "Iconos" - ) + MENU_ENUM_LABEL_VALUE_QT_VIEW, + "Vista" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_LIST, - "Lista" - ) + MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_ICONS, + "Iconos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QUICK_MENU_OVERRIDE_OPTIONS, - "Personalizaciones" - ) + MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_LIST, + "Lista" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_QUICK_MENU_OVERRIDE_OPTIONS, - "Opciones para anular las configuraciones globales" - ) + MENU_ENUM_LABEL_VALUE_QUICK_MENU_OVERRIDE_OPTIONS, + "Personalizaciones" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY, - "Comenzara la reproducción de audio. Al finalizar, será quitado de la memoria" - ) + MENU_ENUM_SUBLABEL_QUICK_MENU_OVERRIDE_OPTIONS, + "Opciones para anular las configuraciones globales" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_LOOPED, - "Comenzara la reproducción de audio. Al finalizar, será reproducido nuevamente" - ) + MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY, + "Comenzara la reproducción de audio. Al finalizar, será quitado de la memoria" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_SEQUENTIAL, - "Comenzara la reproducción de audio. Al finalizar, continuará con el siguiente, útil para albums" - ) + MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_LOOPED, + "Comenzara la reproducción de audio. Al finalizar, será reproducido nuevamente" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIXER_ACTION_STOP, - "Detener la reproducción, no lo quitará de la memoria. Puedes continuar la reproducción" - ) + MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_SEQUENTIAL, + "Comenzara la reproducción de audio. Al finalizar, continuará con el siguiente, útil para albums" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIXER_ACTION_REMOVE, - "Detener la reproducción y quitarlo de la memoria" - ) + MENU_ENUM_SUBLABEL_MIXER_ACTION_STOP, + "Detener la reproducción, no lo quitará de la memoria. Puedes continuar la reproducción" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, - "Ajusta el volumen del audio" - ) + MENU_ENUM_SUBLABEL_MIXER_ACTION_REMOVE, + "Detener la reproducción y quitarlo de la memoria" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ADD_TO_MIXER, - "Agrega esta pista de audio a una casilla, si no hay disponibles, se ignorará" - ) + MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, + "Ajusta el volumen del audio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ADD_TO_MIXER_AND_PLAY, - "Agrega esta pista de audio a una casilla, y la reproduce, si no hay disponibles, se ignorará" - ) + MENU_ENUM_SUBLABEL_ADD_TO_MIXER, + "Agrega esta pista de audio a una casilla, si no hay disponibles, se ignorará" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY, - "Reproducir" - ) + MENU_ENUM_SUBLABEL_ADD_TO_MIXER_AND_PLAY, + "Agrega esta pista de audio a una casilla, y la reproduce, si no hay disponibles, se ignorará" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_LOOPED, - "Reproducir (Repetir)" - ) + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY, + "Reproducir" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_SEQUENTIAL, - "Reproducir (Secuencial)" - ) + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_LOOPED, + "Reproducir (Repetir)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIXER_ACTION_STOP, - "Detener" - ) + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_SEQUENTIAL, + "Reproducir (Secuencial)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIXER_ACTION_REMOVE, - "Quitar" - ) + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_STOP, + "Detener" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIXER_ACTION_VOLUME, - "Volumen" - ) + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_REMOVE, + "Quitar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DETECT_CORE_LIST_OK_CURRENT_CORE, - "Núcleo actual" - ) + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_VOLUME, + "Volumen" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, - "Limpiar" - ) + MENU_ENUM_LABEL_VALUE_DETECT_CORE_LIST_OK_CURRENT_CORE, + "Núcleo actual" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE, - "Pausar logros por esta sesión (Esto activará los archivos de guardado, cámara lenta, trucos, rebobinado y pausa)" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, + "Limpiar" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, - "Continuar los logros para esta sesión (Esto desactivará los archivos de guardado, cámara lenta, trucos, rebobinado y pausa)" - ) + MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE, + "Pausar logros por esta sesión (Esto activará los archivos de guardado, cámara lenta, trucos, rebobinado y pausa)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, - "En-Menú" - ) + MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, + "Continuar los logros para esta sesión (Esto desactivará los archivos de guardado, cámara lenta, trucos, rebobinado y pausa)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, - "Activar Discord" - ) + MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, + "En-Menú" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DISCORD_ALLOW, - "Activar o desactivar soporte de Discord. No funcionará en la versión web de RetroArch, solo en el cliente de escritorio" - ) + MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, + "Activar Discord" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIDI_INPUT, - "Entrada" - ) + MENU_ENUM_SUBLABEL_DISCORD_ALLOW, + "Activar o desactivar soporte de Discord. No funcionará en la versión web de RetroArch, solo en el cliente de escritorio" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIDI_INPUT, - "Seleccionar dispositivo de entrada" - ) + MENU_ENUM_LABEL_VALUE_MIDI_INPUT, + "Entrada" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIDI_OUTPUT, - "Salida" - ) + MENU_ENUM_SUBLABEL_MIDI_INPUT, + "Seleccionar dispositivo de entrada" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIDI_OUTPUT, - "Seleccionar dispositivo de salida" - ) + MENU_ENUM_LABEL_VALUE_MIDI_OUTPUT, + "Salida" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_MIDI_VOLUME, - "Volumen" - ) + MENU_ENUM_SUBLABEL_MIDI_OUTPUT, + "Seleccionar dispositivo de salida" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIDI_VOLUME, - "Establecer volumen de salida (%)" - ) + MENU_ENUM_LABEL_VALUE_MIDI_VOLUME, + "Volumen" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_POWER_MANAGEMENT_SETTINGS, - "Energía" - ) + MENU_ENUM_SUBLABEL_MIDI_VOLUME, + "Establecer volumen de salida (%)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_POWER_MANAGEMENT_SETTINGS, - "Cambiar opciones de energía" - ) + MENU_ENUM_LABEL_VALUE_POWER_MANAGEMENT_SETTINGS, + "Energía" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SUSTAINED_PERFORMANCE_MODE, - "Modo de rendimiento sostenido" - ) + MENU_ENUM_SUBLABEL_POWER_MANAGEMENT_SETTINGS, + "Cambiar opciones de energía" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_MPV_SUPPORT, - "Soporte de mpv" - ) + MENU_ENUM_LABEL_VALUE_SUSTAINED_PERFORMANCE_MODE, + "Modo de rendimiento sostenido" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_IDX, - "Indice" - ) + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_MPV_SUPPORT, + "Soporte de mpv" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_MATCH_IDX, - "Ver coincidencia #" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_IDX, + "Indice" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_MATCH, - "Coindidir dirección: %08X Máscara: %02X" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_MATCH_IDX, + "Ver coincidencia #" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_COPY_MATCH, - "Crear truco de coincidencia #" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_MATCH, + "Coindidir dirección: %08X Máscara: %02X" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_MATCH, - "Borrar coincidencia #" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_MATCH, + "Crear truco de coincidencia #" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_DESC, - "Descripción" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_MATCH, + "Borrar coincidencia #" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_STATE, - "Activado" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_BROWSE_MEMORY, + "Examinar dirección: %08X" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_CODE, - "Truco" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_DESC, + "Descripción" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_HANDLER, - "Manipulador" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_STATE, + "Activado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_MEMORY_SEARCH_SIZE, - "Tamaño de la memoria de búsqueda" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_CODE, + "Truco" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_TYPE, - "Tipo" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_HANDLER, + "Manipulador" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_VALUE, - "Valor" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_MEMORY_SEARCH_SIZE, + "Tamaño de la memoria de búsqueda" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS, - "Dirección de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_TYPE, + "Tipo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS_BIT_POSITION, - "Máscara de la dirección de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_VALUE, + "Valor" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_TYPE, - "Vibrar cuando memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS, + "Dirección de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_VALUE, - "Valor de vibración" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS_BIT_POSITION, + "Máscara de la dirección de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PORT, - "Puerto de vibración" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_TYPE, + "Vibrar cuando memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_STRENGTH, - "Fuerza primaria de vibración" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_VALUE, + "Valor de vibración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_DURATION, - "Duración (ms) de la vibración primaria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PORT, + "Puerto de vibración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_STRENGTH, - "Fuerza secundaria de vibración" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_STRENGTH, + "Fuerza primaria de vibración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_DURATION, - "Duración (ms) de la vibración secundaria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_DURATION, + "Duración (ms) de la vibración primaria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_AFTER, - "Agregar nuevo truco después de este" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_STRENGTH, + "Fuerza secundaria de vibración" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BEFORE, - "Agregar nuevo truco antes de este" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_DURATION, + "Duración (ms) de la vibración secundaria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_COPY_AFTER, - "Copiar este truco después" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_AFTER, + "Agregar nuevo truco después de este" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_COPY_BEFORE, - "Copiar este truco antes" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BEFORE, + "Agregar nuevo truco antes de este" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_DELETE, - "Borrar este truco" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_AFTER, + "Copiar este truco después" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_EMU, - "Emulador" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_BEFORE, + "Copiar este truco antes" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_RETRO, - "RetroArch" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE, + "Borrar este truco" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_TYPE_DISABLED, - "" - ) + MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_EMU, + "Emulador" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_TYPE_SET_TO_VALUE, - "Establecer valor" - ) + MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_RETRO, + "RetroArch" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_TYPE_INCREASE_VALUE, - "Aumentar por valor" - ) + MENU_ENUM_LABEL_CHEAT_TYPE_DISABLED, + "" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_TYPE_DECREASE_VALUE, - "Disminuir por valor" - ) + MENU_ENUM_LABEL_CHEAT_TYPE_SET_TO_VALUE, + "Establecer valor" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_EQ, - "Ejecutar siguiente truco si el valor es igual a la memoria" - ) + MENU_ENUM_LABEL_CHEAT_TYPE_INCREASE_VALUE, + "Aumentar por valor" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_NEQ, - "Ejecutar siguiente truco si el valor es distinto a la memoria" - ) + MENU_ENUM_LABEL_CHEAT_TYPE_DECREASE_VALUE, + "Disminuir por valor" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_LT, - "Ejecutar el siguiente truco si el valor es menor a la memoria" - ) + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_EQ, + "Ejecutar siguiente truco si el valor es igual a la memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_GT, - "Ejecutar el siguiente truco si el valor es mayor a la memoria" - ) + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_NEQ, + "Ejecutar siguiente truco si el valor es distinto a la memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_TYPE_DISABLED, - "" - ) + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_LT, + "Ejecutar el siguiente truco si el valor es menor a la memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_TYPE_CHANGES, - "Cambios" - ) + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_GT, + "Ejecutar el siguiente truco si el valor es mayor a la memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_TYPE_DOES_NOT_CHANGE, - "No cambia" - ) + MENU_ENUM_LABEL_RUMBLE_TYPE_DISABLED, + "" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_TYPE_INCREASE, - "Aumenta" - ) + MENU_ENUM_LABEL_RUMBLE_TYPE_CHANGES, + "Cambios" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_TYPE_DECREASE, - "Disminuye" - ) + MENU_ENUM_LABEL_RUMBLE_TYPE_DOES_NOT_CHANGE, + "No cambia" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_TYPE_EQ_VALUE, - "Igual al valor de vibración" - ) + MENU_ENUM_LABEL_RUMBLE_TYPE_INCREASE, + "Aumenta" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_TYPE_NEQ_VALUE, - "Distinto al valor de vibración" - ) + MENU_ENUM_LABEL_RUMBLE_TYPE_DECREASE, + "Disminuye" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_TYPE_LT_VALUE, - "Menor al valor de vibración" - ) + MENU_ENUM_LABEL_RUMBLE_TYPE_EQ_VALUE, + "Igual al valor de vibración" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_TYPE_GT_VALUE, - "Mayor al valor de vibración" - ) + MENU_ENUM_LABEL_RUMBLE_TYPE_NEQ_VALUE, + "Distinto al valor de vibración" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_1, - "1-bit, valor máx. = 0x01" - ) + MENU_ENUM_LABEL_RUMBLE_TYPE_LT_VALUE, + "Menor al valor de vibración" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_2, - "2-bit, valor máx. = 0x03" - ) + MENU_ENUM_LABEL_RUMBLE_TYPE_GT_VALUE, + "Mayor al valor de vibración" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_4, - "4-bit, valor máx. = 0x0F" - ) + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_1, + "1-bit, valor máx. = 0x01" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_8, - "8-bit, valor máx. = 0xFF" - ) + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_2, + "2-bit, valor máx. = 0x03" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_16, - "16-bit, valor máx. = 0xFFFF" - ) + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_4, + "4-bit, valor máx. = 0x0F" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_32, - "32-bit, valor máx. = 0xFFFFFFFF" - ) + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_8, + "8-bit, valor máx. = 0xFF" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_0, - "1" - ) + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_16, + "16-bit, valor máx. = 0xFFFF" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_1, - "2" - ) + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_32, + "32-bit, valor máx. = 0xFFFFFFFF" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_2, - "3" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_0, + "1" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_3, - "4" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_1, + "2" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_4, - "5" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_2, + "3" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_5, - "6" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_3, + "4" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_6, - "7" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_4, + "5" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_7, - "8" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_5, + "6" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_8, - "9" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_6, + "7" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_9, - "10" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_7, + "8" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_10, - "11" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_8, + "9" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_11, - "12" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_9, + "10" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_12, - "13" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_10, + "11" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_13, - "14" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_11, + "12" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_14, - "15" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_12, + "13" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_15, - "16" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_13, + "14" + ) MSG_HASH( - MENU_ENUM_LABEL_RUMBLE_PORT_16, - "All" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_14, + "15" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_CONT, - "Inciar o continuar búsqueda de trucos" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_15, + "16" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_RESTART, - "Inciar o reiniciar búsqueda de trucos" - ) + MENU_ENUM_LABEL_RUMBLE_PORT_16, + "All" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EXACT, - "Buscar valores de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_CONT, + "Inciar o continuar búsqueda de trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LT, - "Buscar valores de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_RESTART, + "Inciar o reiniciar búsqueda de trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GT, - "Buscar valores de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EXACT, + "Buscar valores de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQ, - "Buscar valores de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LT, + "Buscar valores de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GTE, - "Buscar valores de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GT, + "Buscar valores de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LTE, - "Buscar valores de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQ, + "Buscar valores de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_NEQ, - "Buscar valores de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GTE, + "Buscar valores de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQPLUS, - "Buscar valores de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LTE, + "Buscar valores de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQMINUS, - "Buscar valores de memoria" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_NEQ, + "Buscar valores de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_ADD_MATCHES, - "Agregar las %u coincidencias a tu lista" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQPLUS, + "Buscar valores de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, - "Ver lista de %u coincidencias" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQMINUS, + "Buscar valores de memoria" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_CREATE_OPTION, - "Crear truco de esta coincidencia" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_MATCHES, + "Agregar las %u coincidencias a tu lista" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_OPTION, - "Borrar esta coincidencia" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, + "Ver lista de %u coincidencias" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_TOP, - "Agregar nuevo truco al principio" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_CREATE_OPTION, + "Crear truco de esta coincidencia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BOTTOM, - "Agregar nuevo truco al final" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_OPTION, + "Borrar esta coincidencia" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_ALL, - "Borrar todos los trucos" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_TOP, + "Agregar nuevo truco al principio" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_SEARCH_EXACT_VAL, - "Igual a %u (%X)" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BOTTOM, + "Agregar nuevo truco al final" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_SEARCH_LT_VAL, - "Menos que antes" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_ALL, + "Borrar todos los trucos" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_SEARCH_GT_VAL, - "Más que antes" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_RELOAD_CHEATS, + "Recargar trucos específicos del juego" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_SEARCH_LTE_VAL, - "Menos o igual que antes" - ) + MENU_ENUM_LABEL_CHEAT_SEARCH_EXACT_VAL, + "Igual a %u (%X)" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_SEARCH_GTE_VAL, - "Más o igual que antes" - ) + MENU_ENUM_LABEL_CHEAT_SEARCH_LT_VAL, + "Menos que antes" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_SEARCH_EQ_VAL, - "Igual que antes" - ) + MENU_ENUM_LABEL_CHEAT_SEARCH_GT_VAL, + "Más que antes" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_SEARCH_NEQ_VAL, - "Distinto que antes" - ) + MENU_ENUM_LABEL_CHEAT_SEARCH_LTE_VAL, + "Menos o igual que antes" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_SEARCH_EQPLUS_VAL, - "Igual que antes+%u (%X)" - ) + MENU_ENUM_LABEL_CHEAT_SEARCH_GTE_VAL, + "Más o igual que antes" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_SEARCH_EQMINUS_VAL, - "Igual que antes-%u (%X)" - ) + MENU_ENUM_LABEL_CHEAT_SEARCH_EQ_VAL, + "Igual que antes" + ) MSG_HASH( - MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS, - "Iniciar o continuar búsqueda de trucos" - ) + MENU_ENUM_LABEL_CHEAT_SEARCH_NEQ_VAL, + "Distinto que antes" + ) MSG_HASH( - MSG_CHEAT_INIT_SUCCESS, - "Búsqueda de trucos iniciada correctamente" - ) + MENU_ENUM_LABEL_CHEAT_SEARCH_EQPLUS_VAL, + "Igual que antes+%u (%X)" + ) MSG_HASH( - MSG_CHEAT_INIT_FAIL, - "Fallo al iniciar búsqueda de trucos" - ) + MENU_ENUM_LABEL_CHEAT_SEARCH_EQMINUS_VAL, + "Igual que antes-%u (%X)" + ) MSG_HASH( - MSG_CHEAT_SEARCH_NOT_INITIALIZED, - "La búsqueda no ha sido iniciada" - ) + MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS, + "Iniciar o continuar búsqueda de trucos" + ) MSG_HASH( - MSG_CHEAT_SEARCH_FOUND_MATCHES, - "Número de coincidencias = %u" - ) + MSG_CHEAT_INIT_SUCCESS, + "Búsqueda de trucos iniciada correctamente" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_BIG_ENDIAN, - "Big Endian" - ) + MSG_CHEAT_INIT_FAIL, + "Fallo al iniciar búsqueda de trucos" + ) MSG_HASH( - MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS, - "Agregadas %u coincidencias" - ) + MSG_CHEAT_SEARCH_NOT_INITIALIZED, + "La búsqueda no ha sido iniciada" + ) MSG_HASH( - MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL, - "Fallo al agregar coincidencias" - ) + MSG_CHEAT_SEARCH_FOUND_MATCHES, + "Número de coincidencias = %u" + ) MSG_HASH( - MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS, - "Truco creado desde coincidencia" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_BIG_ENDIAN, + "Big Endian" + ) MSG_HASH( - MSG_CHEAT_SEARCH_ADD_MATCH_FAIL, - "Fallo al crear truco" - ) + MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS, + "Agregadas %u coincidencias" + ) MSG_HASH( - MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS, - "Borrar coincidencia" - ) + MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL, + "Fallo al agregar coincidencias" + ) MSG_HASH( - MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY, - "No hay suficiente espacio. El máximo es 100 trucos" - ) + MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS, + "Truco creado desde coincidencia" + ) MSG_HASH( - MSG_CHEAT_ADD_TOP_SUCCESS, - "Nuevo truco agregado al inicio de la lista" - ) + MSG_CHEAT_SEARCH_ADD_MATCH_FAIL, + "Fallo al crear truco" + ) MSG_HASH( - MSG_CHEAT_ADD_BOTTOM_SUCCESS, - "Nuevo truco agregado al final de la lista" - ) + MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS, + "Borrar coincidencia" + ) MSG_HASH( - MSG_CHEAT_DELETE_ALL_INSTRUCTIONS, - "Presiona derecha cinco veces para borrar todos los trucos" - ) + MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY, + "No hay suficiente espacio. El máximo es 100 trucos" + ) MSG_HASH( - MSG_CHEAT_DELETE_ALL_SUCCESS, - "Todos los trucos fueron borrados" - ) + MSG_CHEAT_ADD_TOP_SUCCESS, + "Nuevo truco agregado al inicio de la lista" + ) MSG_HASH( - MSG_CHEAT_ADD_BEFORE_SUCCESS, - "Nuevo truco agregado antes de este" - ) + MSG_CHEAT_ADD_BOTTOM_SUCCESS, + "Nuevo truco agregado al final de la lista" + ) MSG_HASH( - MSG_CHEAT_ADD_AFTER_SUCCESS, - "Nuevo truco agregado después de este" - ) + MSG_CHEAT_DELETE_ALL_INSTRUCTIONS, + "Presiona derecha cinco veces para borrar todos los trucos" + ) MSG_HASH( - MSG_CHEAT_COPY_BEFORE_SUCCESS, - "Truco copiado antes de este" - ) + MSG_CHEAT_DELETE_ALL_SUCCESS, + "Todos los trucos fueron borrados" + ) MSG_HASH( - MSG_CHEAT_COPY_AFTER_SUCCESS, - "Truco copiado después de este" - ) + MSG_CHEAT_ADD_BEFORE_SUCCESS, + "Nuevo truco agregado antes de este" + ) MSG_HASH( - MSG_CHEAT_DELETE_SUCCESS, - "Truco borrado" - ) + MSG_CHEAT_ADD_AFTER_SUCCESS, + "Nuevo truco agregado después de este" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_PROGRESS, - "Progreso:" - ) + MSG_CHEAT_COPY_BEFORE_SUCCESS, + "Truco copiado antes de este" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT, - "\"Todas la Playlists\" máximo de entradas en lista:" - ) + MSG_CHEAT_COPY_AFTER_SUCCESS, + "Truco copiado después de este" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT, - "\"Todas la Playlists\" máximo de entradas en grilla:" - ) + MSG_CHEAT_DELETE_SUCCESS, + "Truco borrado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES, - "Mostrar elementos ocultos" - ) + MENU_ENUM_LABEL_VALUE_QT_PROGRESS, + "Progreso:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST, - "Nueva Playlist" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT, + "\"Todas la Playlists\" máximo de entradas en lista:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME, - "Por favor ingrese el nombre de la nueva Playlist:" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT, + "\"Todas la Playlists\" máximo de entradas en grilla:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST, - "Borrar Playlist" - ) + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES, + "Mostrar elementos ocultos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, - "¿Está seguro que desea borrar la playlist \"%1\"?" - ) + MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST, + "Nueva Playlist" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_QUESTION, - "Pregunta" - ) + MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME, + "Por favor ingrese el nombre de la nueva Playlist:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, - "No se pudo borrar el archivo" - ) + MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST, + "Borrar Playlist" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, - "Cargando lista de archivos..." - ) + MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, + "¿Está seguro que desea borrar la playlist \"%1\"?" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, - "Agregando archivos a la Playlist..." - ) + MENU_ENUM_LABEL_VALUE_QT_QUESTION, + "Pregunta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY, - "Entrada de la Playlist" - ) + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, + "No se pudo borrar el archivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE, - "Núcleo:" - ) + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE, + "No se pudo renombrar el archivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, - "Base de datos:" - ) + MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, + "Cargando lista de archivos..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, - "(usado pata buscar miniaturas)" - ) + MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, + "Agregando archivos a la Playlist..." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM, - "¿Está seguro que desea borrar \"%1\"?" - ) + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY, + "Entrada de la Playlist" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS, - "Por favor primero elija solo una Playlist" - ) + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_NAME, + "Nombre:" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_QT_DELETE, - "Borrar" - ) + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_PATH, + "Ruta:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE, + "Núcleo:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, + "Base de datos:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, + "(usado pata buscar miniaturas)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM, + "¿Está seguro que desea borrar \"%1\"?" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS, + "Por favor primero elija solo una Playlist" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DELETE, + "Borrar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_ENTRY, + "Agregar entrada..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_FILES, + "Agregar archivo(s)..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_FOLDER, + "Agregar carpeta..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_EDIT, + "Editar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SELECT_FILES, + "Seleccionar archivos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SELECT_FOLDER, + "Seleccionar carpeta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY, + "Error actualizando la entrada de la playlist" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS, + "Por favor rellene todos los campos obligatorios" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY, + "Actualizar RetroArch (nightly)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED, + "RetroArch actualizado correctamente. Reinicie la aplicación para que los cambios tengan efecto" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, + "Actualización fallida" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT_CONTRIBUTORS, + "Contribuyentes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, + "Shader actual" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, + "Mover abajo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, + "Mover arriba" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOAD, + "Cargar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SAVE, + "Save" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_REMOVE, + "Quitar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_APPLY, + "Aplicar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, + "Agregar pasada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, + "Quitar todas las pasadas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, + "No hay pasadas de shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_PASS, + "Restablecer pasada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, + "Restablecer todas las pasadas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, + "Restablecer parámetro" + ) \ No newline at end of file From fad5569d99d365ab2244d62e0976e25a094afaf5 Mon Sep 17 00:00:00 2001 From: Alfrix Date: Tue, 21 Aug 2018 15:28:36 -0300 Subject: [PATCH 123/182] Cleanup styling --- intl/msg_hash_us.h | 11300 +++++++++++++++++++++++++++---------------- 1 file changed, 7188 insertions(+), 4112 deletions(-) diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 82a406bc13..8e6649c1b7 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -1,4292 +1,7368 @@ MSG_HASH( - MSG_COMPILER, - "Compiler" - ) + MSG_COMPILER, + "Compiler" + ) MSG_HASH( - MSG_UNKNOWN_COMPILER, - "Unknown compiler" - ) + MSG_UNKNOWN_COMPILER, + "Unknown compiler" + ) MSG_HASH( - MSG_DEVICE_DISCONNECTED_FROM_PORT, - "Device disconnected from port" - ) + MSG_DEVICE_DISCONNECTED_FROM_PORT, + "Device disconnected from port" + ) MSG_HASH( - MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, - "Unknown netplay command received" - ) + MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, + "Unknown netplay command received" + ) MSG_HASH( - MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, - "File already exists. Saving to backup buffer" - ) + MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, + "File already exists. Saving to backup buffer" + ) MSG_HASH( - MSG_GOT_CONNECTION_FROM, - "Got connection from: \"%s\"" - ) + MSG_GOT_CONNECTION_FROM, + "Got connection from: \"%s\"" + ) MSG_HASH( - MSG_GOT_CONNECTION_FROM_NAME, - "Got connection from: \"%s (%s)\"" - ) + MSG_GOT_CONNECTION_FROM_NAME, + "Got connection from: \"%s (%s)\"" + ) MSG_HASH( - MSG_PUBLIC_ADDRESS, - "Public address" - ) + MSG_PUBLIC_ADDRESS, + "Public address" + ) MSG_HASH( - MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, - "No arguments supplied and no menu builtin, displaying help..." - ) + MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, + "No arguments supplied and no menu builtin, displaying help..." + ) MSG_HASH( - MSG_SETTING_DISK_IN_TRAY, - "Setting disk in tray" - ) + MSG_SETTING_DISK_IN_TRAY, + "Setting disk in tray" + ) MSG_HASH( - MSG_WAITING_FOR_CLIENT, - "Waiting for client ..." - ) + MSG_WAITING_FOR_CLIENT, + "Waiting for client ..." + ) MSG_HASH( - MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME, - "You have left the game" - ) + MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME, + "You have left the game" + ) MSG_HASH( - MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, - "You have joined as player %u" - ) + MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, + "You have joined as player %u" + ) MSG_HASH( - MSG_NETPLAY_YOU_HAVE_JOINED_WITH_INPUT_DEVICES_S, - "You have joined with input devices %.*s" - ) + MSG_NETPLAY_YOU_HAVE_JOINED_WITH_INPUT_DEVICES_S, + "You have joined with input devices %.*s" + ) MSG_HASH( - MSG_NETPLAY_PLAYER_S_LEFT, - "Player %.*s has left the game" - ) + MSG_NETPLAY_PLAYER_S_LEFT, + "Player %.*s has left the game" + ) MSG_HASH( - MSG_NETPLAY_S_HAS_JOINED_AS_PLAYER_N, - "%.*s has joined as player %u" - ) + MSG_NETPLAY_S_HAS_JOINED_AS_PLAYER_N, + "%.*s has joined as player %u" + ) MSG_HASH( - MSG_NETPLAY_S_HAS_JOINED_WITH_INPUT_DEVICES_S, - "%.*s has joined with input devices %.*s" - ) + MSG_NETPLAY_S_HAS_JOINED_WITH_INPUT_DEVICES_S, + "%.*s has joined with input devices %.*s" + ) MSG_HASH( - MSG_NETPLAY_NOT_RETROARCH, - "A netplay connection attempt failed because the peer is not running RetroArch, or is running an old version of RetroArch." - ) + MSG_NETPLAY_NOT_RETROARCH, + "A netplay connection attempt failed because the peer is not running RetroArch, or is running an old version of RetroArch." + ) MSG_HASH( - MSG_NETPLAY_OUT_OF_DATE, - "The netplay peer is running an old version of RetroArch. Cannot connect." - ) + MSG_NETPLAY_OUT_OF_DATE, + "The netplay peer is running an old version of RetroArch. Cannot connect." + ) MSG_HASH( - MSG_NETPLAY_DIFFERENT_VERSIONS, - "WARNING: A netplay peer is running a different version of RetroArch. If problems occur, use the same version." - ) + MSG_NETPLAY_DIFFERENT_VERSIONS, + "WARNING: A netplay peer is running a different version of RetroArch. If problems occur, use the same version." + ) MSG_HASH( - MSG_NETPLAY_DIFFERENT_CORES, - "A netplay peer is running a different core. Cannot connect." - ) + MSG_NETPLAY_DIFFERENT_CORES, + "A netplay peer is running a different core. Cannot connect." + ) MSG_HASH( - MSG_NETPLAY_DIFFERENT_CORE_VERSIONS, - "WARNING: A netplay peer is running a different version of the core. If problems occur, use the same version." - ) + MSG_NETPLAY_DIFFERENT_CORE_VERSIONS, + "WARNING: A netplay peer is running a different version of the core. If problems occur, use the same version." + ) MSG_HASH( - MSG_NETPLAY_ENDIAN_DEPENDENT, - "This core does not support inter-architecture netplay between these systems" - ) + MSG_NETPLAY_ENDIAN_DEPENDENT, + "This core does not support inter-architecture netplay between these systems" + ) MSG_HASH( - MSG_NETPLAY_PLATFORM_DEPENDENT, - "This core does not support inter-architecture netplay" - ) + MSG_NETPLAY_PLATFORM_DEPENDENT, + "This core does not support inter-architecture netplay" + ) MSG_HASH( - MSG_NETPLAY_ENTER_PASSWORD, - "Enter netplay server password:" - ) + MSG_NETPLAY_ENTER_PASSWORD, + "Enter netplay server password:" + ) MSG_HASH( - MSG_NETPLAY_INCORRECT_PASSWORD, - "Incorrect password" - ) + MSG_NETPLAY_INCORRECT_PASSWORD, + "Incorrect password" + ) MSG_HASH( - MSG_NETPLAY_SERVER_NAMED_HANGUP, - "\"%s\" has disconnected" - ) + MSG_NETPLAY_SERVER_NAMED_HANGUP, + "\"%s\" has disconnected" + ) MSG_HASH( - MSG_NETPLAY_SERVER_HANGUP, - "A netplay client has disconnected" - ) + MSG_NETPLAY_SERVER_HANGUP, + "A netplay client has disconnected" + ) MSG_HASH( - MSG_NETPLAY_CLIENT_HANGUP, - "Netplay disconnected" - ) + MSG_NETPLAY_CLIENT_HANGUP, + "Netplay disconnected" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, - "You do not have permission to play" - ) + MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, + "You do not have permission to play" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, - "There are no free player slots" - ) + MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, + "There are no free player slots" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY_NOT_AVAILABLE, - "The input devices requested are not available" - ) + MSG_NETPLAY_CANNOT_PLAY_NOT_AVAILABLE, + "The input devices requested are not available" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY, - "Cannot switch to play mode" - ) + MSG_NETPLAY_CANNOT_PLAY, + "Cannot switch to play mode" + ) MSG_HASH( - MSG_NETPLAY_PEER_PAUSED, - "Netplay peer \"%s\" paused" - ) + MSG_NETPLAY_PEER_PAUSED, + "Netplay peer \"%s\" paused" + ) MSG_HASH( - MSG_NETPLAY_CHANGED_NICK, - "Your nickname changed to \"%s\"" - ) + MSG_NETPLAY_CHANGED_NICK, + "Your nickname changed to \"%s\"" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, - "Give hardware-rendered cores their own private context. Avoids having to assume hardware state changes inbetween frames." - ) + MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, + "Give hardware-rendered cores their own private context. Avoids having to assume hardware state changes inbetween frames." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SETTINGS, - "Adjusts menu screen appearance settings." - ) + MENU_ENUM_SUBLABEL_MENU_SETTINGS, + "Adjusts menu screen appearance settings." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, - "Hard-synchronize the CPU and GPU. Reduces latency at the cost of performance." - ) + MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, + "Hard-synchronize the CPU and GPU. Reduces latency at the cost of performance." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_THREADED, - "Improves performance at the cost of latency and more video stuttering. Use only if you cannot obtain full speed otherwise." - ) + MENU_ENUM_SUBLABEL_VIDEO_THREADED, + "Improves performance at the cost of latency and more video stuttering. Use only if you cannot obtain full speed otherwise." + ) MSG_HASH( - MSG_AUDIO_VOLUME, - "Audio volume" - ) + MSG_AUDIO_VOLUME, + "Audio volume" + ) MSG_HASH( - MSG_AUTODETECT, - "Autodetect" - ) + MSG_AUTODETECT, + "Autodetect" + ) MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Auto-loading savestate from" - ) + MSG_AUTOLOADING_SAVESTATE_FROM, + "Auto-loading savestate from" + ) MSG_HASH( - MSG_CAPABILITIES, - "Capabilities" - ) + MSG_CAPABILITIES, + "Capabilities" + ) MSG_HASH( - MSG_CONNECTING_TO_NETPLAY_HOST, - "Connecting to netplay host" - ) + MSG_CONNECTING_TO_NETPLAY_HOST, + "Connecting to netplay host" + ) MSG_HASH( - MSG_CONNECTING_TO_PORT, - "Connecting to port" - ) + MSG_CONNECTING_TO_PORT, + "Connecting to port" + ) MSG_HASH( - MSG_CONNECTION_SLOT, - "Connection slot" - ) + MSG_CONNECTION_SLOT, + "Connection slot" + ) MSG_HASH( - MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, - "Sorry, unimplemented: cores that don't demand content cannot participate in netplay." - ) + MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, + "Sorry, unimplemented: cores that don't demand content cannot participate in netplay." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, - "Password" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, + "Password" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, - "Accounts Cheevos" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, + "Accounts Cheevos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, - "Username" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, + "Username" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, - "Accounts" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, + "Accounts" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, - "Accounts List Endpoint" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, + "Accounts List Endpoint" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, - "RetroAchievements" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, + "RetroAchievements" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, - "Achievements" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, + "Achievements" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE, - "Pause Achievements Hardcore Mode" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE, + "Pause Achievements Hardcore Mode" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME, - "Resume Achievements Hardcore Mode" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME, + "Resume Achievements Hardcore Mode" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "Achievements (Hardcore)" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, + "Achievements (Hardcore)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, - "Scan Content" - ) + MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, + "Scan Content" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, - "Configurations" - ) + MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, + "Configurations" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_TAB, - "Import content" - ) + MENU_ENUM_LABEL_VALUE_ADD_TAB, + "Import content" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, - "Netplay Rooms" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, + "Netplay Rooms" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, - "Ask" - ) + MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, + "Ask" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, - "Assets" - ) + MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, + "Assets" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, - "Block Frames" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, + "Block Frames" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, - "Audio Device" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, + "Audio Device" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, - "Audio Driver" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, + "Audio Driver" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, - "Audio DSP Plugin" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, + "Audio DSP Plugin" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, - "Audio Enable" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, + "Audio Enable" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, - "Audio Filter" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, + "Audio Filter" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, - "Turbo/Deadzone" - ) + MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, + "Turbo/Deadzone" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, - "Audio Latency (ms)" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, + "Audio Latency (ms)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, - "Audio Maximum Timing Skew" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, + "Audio Maximum Timing Skew" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, - "Audio Mute" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, + "Audio Mute" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, - "Audio Output Rate (Hz)" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, + "Audio Output Rate (Hz)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, - "Dynamic Audio Rate Control" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, + "Dynamic Audio Rate Control" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, - "Audio Resampler Driver" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, + "Audio Resampler Driver" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, - "Audio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, + "Audio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, - "Audio Sync" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, + "Audio Sync" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, - "Audio Volume Level (dB)" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, + "Audio Volume Level (dB)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_EXCLUSIVE_MODE, - "WASAPI Exclusive Mode" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_EXCLUSIVE_MODE, + "WASAPI Exclusive Mode" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_FLOAT_FORMAT, - "WASAPI Float Format" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_FLOAT_FORMAT, + "WASAPI Float Format" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_SH_BUFFER_LENGTH, - "WASAPI Shared Buffer Length" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_SH_BUFFER_LENGTH, + "WASAPI Shared Buffer Length" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, - "SaveRAM Autosave Interval" - ) + MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, + "SaveRAM Autosave Interval" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, - "Load Override Files Automatically" - ) + MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, + "Load Override Files Automatically" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, - "Load Remap Files Automatically" - ) + MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, + "Load Remap Files Automatically" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, - "Load Shader Presets Automatically" - ) + MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, + "Load Shader Presets Automatically" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, - "Back" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, + "Back" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, - "Confirm" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, + "Confirm" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, - "Info" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, + "Info" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, - "Quit" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, + "Quit" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, - "Scroll Down" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, + "Scroll Down" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, - "Scroll Up" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, + "Scroll Up" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, - "Start" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, + "Start" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, - "Toggle Keyboard" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, + "Toggle Keyboard" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, - "Toggle Menu" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, + "Toggle Menu" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, - "Basic menu controls" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, + "Basic menu controls" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, - "Confirm/OK" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, + "Confirm/OK" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, - "Info" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, + "Info" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, - "Quit" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, + "Quit" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, - "Scroll Up" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, + "Scroll Up" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, - "Defaults" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, + "Defaults" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_KEYBOARD, - "Toggle Keyboard" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_KEYBOARD, + "Toggle Keyboard" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, - "Toggle Menu" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, + "Toggle Menu" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, - "Don't overwrite SaveRAM on loading savestate" - ) + MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, + "Don't overwrite SaveRAM on loading savestate" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, - "Bluetooth Enable" - ) + MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, + "Bluetooth Enable" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, - "Buildbot Assets URL" - ) + MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, + "Buildbot Assets URL" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, - "Cache" - ) + MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, + "Cache" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, - "Allow Camera" - ) + MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, + "Allow Camera" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, - "Camera Driver" - ) + MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, + "Camera Driver" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT, - "Cheat" - ) + MENU_ENUM_LABEL_VALUE_CHEAT, + "Cheat" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, - "Apply Changes" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, + "Apply Changes" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_START_SEARCH, - "Start Search For New Cheat Code" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_START_SEARCH, + "Start Search For New Cheat Code" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_CONTINUE_SEARCH, - "Continue Search" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_CONTINUE_SEARCH, + "Continue Search" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, - "Cheat File" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, + "Cheat File" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE, - "Cheat File" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_FILE, + "Cheat File" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, - "Load Cheat File (Replace)" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, + "Load Cheat File (Replace)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD_APPEND, - "Load Cheat File (Append)" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, - "Save Cheat File As" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, - "Cheat Passes" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, - "Description" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, - "Hardcore Mode" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_LEADERBOARDS_ENABLE, - "Leaderboards" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_BADGES_ENABLE, - "Achievement Badges" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, - "Locked Achievements:" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY, - "Locked" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_SETTINGS, - "RetroAchievements" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, - "Test Unofficial Achievements" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, - "Unlocked Achievements:" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY, - "Unlocked" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, - "Hardcore" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_VERBOSE_ENABLE, - "Verbose Mode" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_AUTO_SCREENSHOT, - "Automatic Screenshot" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, - "Close Content" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIG, - "Config" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, - "Load Configuration" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, - "Configuration" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, - "Save Configuration on Exit" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST, - "Collections" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, - "Database" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_DIR, - "Content" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, - "History List Size") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, - "Allow to remove entries") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, - "Quick Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, - "Downloads") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, - "Downloads") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, - "Cheats") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, - "Core Counters") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ENABLE, - "Show core name") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, - "Core Information") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, - "Authors") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, - "Categories") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL, - "Core label") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME, - "Core name") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, - "Firmware(s)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, - "License(s)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, - "Permissions") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS, - "Supported extensions") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_MANUFACTURER, - "System manufacturer") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, - "System name") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, - "Controls") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_LIST, - "Load Core") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, - "Options") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SETTINGS, - "Core") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SET_SUPPORTS_NO_CONTENT_ENABLE, - "Start a Core Automatically") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, - "Automatically extract downloaded archive") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, - "Buildbot Cores URL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST, - "Core Updater") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, - "Updater") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CPU_ARCHITECTURE, - "CPU Architecture:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CPU_CORES, - "CPU Cores:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CURSOR_DIRECTORY, - "Cursor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CURSOR_MANAGER, - "Cursor Manager") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO, - "Custom Ratio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER, - "Database Manager") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_SELECTION, - "Database Selection") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DELETE_ENTRY, - "Remove") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FAVORITES, - "Start directory") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, - "Directory not found.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS, - "Directory") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS, - "Disk Cycle Tray Status") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, - "Disk Image Append") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_INDEX, - "Disk Index") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, - "Disk Control") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DONT_CARE, - "Don't care") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, - "Downloads") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE, - "Download Core...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT, - "Content Downloader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_ENABLE, - "DPI Override Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_VALUE, - "DPI Override") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, - "Driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, - "Load Dummy on Core Shutdown") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, - "Check for Missing Firmware Before Loading") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, - "Dynamic Background") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, - "Dynamic Backgrounds") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, - "Enable Achievements") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, - "Menu entry hover color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, - "Menu entry normal color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FALSE, - "False") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, - "Maximum Run Speed") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, - "Favorites") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FPS_SHOW, - "Display Framerate") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, - "Limit Maximum Run Speed") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VRR_RUNLOOP_ENABLE, - "Sync to Exact Content Framerate (G-Sync, FreeSync)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, - "Frame Throttle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, - "Frontend Counters") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, - "Load Content-Specific Core Options Automatically") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, - "Create game-options file") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, - "Save Game-options file") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP, - "Help") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, - "Audio/Video Troubleshooting") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, - "Changing Virtual Gamepad Overlay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, - "Basic Menu Controls") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LIST, - "Help") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, - "Loading Content") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, - "Scanning For Content") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, - "What Is A Core?") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, - "History List Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_TAB, - "History") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, - "Horizontal Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_IMAGES_TAB, - "Image") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION, - "Information") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, - "Information") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, - "Analog To Digital Type") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, - "All Users Control Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, - "Left Analog X") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, - "Left analog X- (left)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, - "Left analog X+ (right)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y, - "Left Analog Y") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, - "Left analog Y- (up)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, - "Left analog Y+ (down)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X, - "Right Analog X") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, - "Right analog X- (left)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, - "Right analog X+ (right)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y, - "Right Analog Y") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, - "Right analog Y- (up)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, - "Right analog Y+ (down)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, - "Gun Trigger") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, - "Gun Reload") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A, - "Gun Aux A") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B, - "Gun Aux B") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C, - "Gun Aux C") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START, - "Gun Start") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT, - "Gun Select") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP, - "Gun D-pad Up") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN, - "Gun D-pad Down") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT, - "Gun D-pad Left") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, - "Gun D-pad Right") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, - "Autoconfig Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, - "Analog Stick Deadzone") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, - "Menu Swap OK & Cancel Buttons") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, - "Bind All") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, - "Bind Default All") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_TIMEOUT, - "Bind Timeout") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_HOLD, - "Bind Hold") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_HIDE_UNBOUND, - "Hide Unbound Core Input Descriptors") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW, - "Display Input Descriptor Labels") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, - "Device Index") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, - "Device Type") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, - "Mouse Index") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DRIVER, - "Input Driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Duty Cycle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, - "Input Hotkey Binds") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, - "Keyboard Gamepad Mapping Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, - "A button (right)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, - "B button (down)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, - "Down D-pad") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, - "L2 button (trigger)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, - "L3 button (thumb)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, - "L button (shoulder)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, - "Left D-pad") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, - "R2 button (trigger)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, - "R3 button (thumb)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, - "R button (shoulder)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, - "Right D-pad") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, - "Select button") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, - "Start button") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, - "Up D-pad") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, - "X button (top)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, - "Y button (left)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEY, - "(Key: %s)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_LEFT, - "Mouse 1") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_RIGHT, - "Mouse 2") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_MIDDLE, - "Mouse 3") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON4, - "Mouse 4") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON5, - "Mouse 5") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_UP, - "Wheel Up") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_DOWN, - "Wheel Down") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_UP, - "Wheel Left") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_DOWN, - "Wheel Right") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, - "Keyboard Gamepad Mapping Type") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, - "Max Users") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Menu Toggle Gamepad Combo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, - "Cheat index -") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, - "Cheat index +") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, - "Cheat toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, - "Disk eject toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, - "Disk next") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, - "Disk prev") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, - "Enable hotkeys") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, - "Fast forward hold") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, - "Fast forward toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, - "Frameadvance") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, - "Fullscreen toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, - "Grab mouse toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, - "Game focus toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, - "Desktop menu toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, - "Load state") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, - "Menu toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, - "Movie record toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, - "Audio mute toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, - "Netplay toggle play/spectate mode") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, - "On-screen keyboard toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, - "Overlay next") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, - "Pause toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, - "Quit RetroArch") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, - "Reset game") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, - "Rewind") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_DETAILS, - "Cheat Details") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_SEARCH, - "Start or Continue Cheat Search") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, - "Save state") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, - "Take screenshot") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, - "Next shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, - "Previous shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY, - "Slow motion hold") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY, - "Slow motion toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, - "Savestate slot -") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, - "Savestate slot +") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, - "Volume -") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, - "Volume +") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, - "Display Overlay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, - "Hide Overlay In Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, - "Show Inputs On Overlay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, - "Show Inputs Listen Port") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, - "Poll Type Behavior") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, - "Early") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_LATE, - "Late") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_NORMAL, - "Normal") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_PREFER_FRONT_TOUCH, - "Prefer Front Touch") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, - "Input Remapping") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, - "Remap Binds Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, - "Save Autoconfig") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, - "Input") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, - "Small Keyboard Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_ENABLE, - "Touch Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "Turbo enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, - "Turbo Period") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, - "Input User %u Binds") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LATENCY_SETTINGS, - "Latency") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INTERNAL_STORAGE_STATUS, - "Internal storage status") -MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, - "Input Autoconfig") -MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, - "Joypad Driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, - "Services") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_CHINESE_SIMPLIFIED, - "Chinese (Simplified)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_CHINESE_TRADITIONAL, - "Chinese (Traditional)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_DUTCH, - "Dutch") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ENGLISH, - "English") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ESPERANTO, - "Esperanto") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_FRENCH, - "French") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_GERMAN, - "German") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ITALIAN, - "Italian") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_JAPANESE, - "Japanese") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_KOREAN, - "Korean") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_POLISH, - "Polish") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_BRAZIL, - "Portuguese (Brazil)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_PORTUGAL, - "Portuguese (Portugal)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_RUSSIAN, - "Russian") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH, - "Spanish") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE, - "Vietnamese") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC, - "Arabic") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, - "Left Analog") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, - "Core") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, - "Core Info") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, - "Core Logging Level") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LINEAR, - "Linear") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, - "Load Archive") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, - "Load Recent") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, - "Load Content") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_STATE, - "Load State") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, - "Allow Location") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER, - "Location Driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, - "Logging") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY, - "Logging Verbosity") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MAIN_MENU, - "Main Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MANAGEMENT, - "Database Settings") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, - "Menu Color Theme") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE, - "Blue") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, - "Blue Grey") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_DARK_BLUE, - "Dark Blue") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GREEN, - "Green") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_NVIDIA_SHIELD, - "Shield") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_RED, - "Red") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_YELLOW, - "Yellow") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, - "Footer Opacity") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, - "Header Opacity") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_DRIVER, - "Menu Driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, - "Throttle Menu Framerate") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, - "Settings") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, - "Menu Linear Filter") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, - "Horizontal Animation") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Appearance") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, - "Background") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, - "Background opacity") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MISSING, - "Missing") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MORE, - "...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MOUSE_ENABLE, - "Mouse Support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MULTIMEDIA_SETTINGS, - "Multimedia") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MUSIC_TAB, - "Music") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, - "Filter unknown extensions") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, - "Navigation Wrap-Around") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NEAREST, - "Nearest") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY, - "Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_SLAVES, - "Allow Slave-Mode Clients") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, - "Netplay Check Frames") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, - "Input Latency Frames") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, - "Input Latency Frames Range") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, - "Netplay Delay Frames") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, - "Disconnect from netplay host") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, - "Netplay Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, - "Connect to netplay host") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, - "Start netplay host") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, - "Stop netplay host") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, - "Server Address") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, - "Scan local network") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, - "Netplay Client Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, - "Username") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, - "Server Password") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, - "Publicly Announce Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REQUEST_DEVICE_I, - "Request Device %u") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REQUIRE_SLAVES, - "Disallow Non-Slave-Mode Clients") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, - "Netplay settings") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG, - "Analog Input Sharing") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_MAX, - "Max") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_AVERAGE, - "Average") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL, - "Digital Input Sharing") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_OR, - "Share") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_XOR, - "Grapple") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_VOTE, - "Vote") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NONE, - "None") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NO_PREFERENCE, - "No preference") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_AS_SPECTATOR, - "Netplay Spectator Mode") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, - "Netplay Stateless Mode") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, - "Server Spectate-Only Password") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, - "Netplay Spectator Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, - "Netplay TCP Port") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, - "Netplay NAT Traversal") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, - "Network Commands") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, - "Network Command Port") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION, - "Network Information") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, - "Network Gamepad") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, - "Network Remote Base Port") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, - "Network") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO, - "No") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NONE, - "None") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE, - "N/A") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY, - "No achievements to display.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE, - "No Core") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, - "No cores available.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, - "No core information available.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, - "No core options available.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, - "No entries to display.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, - "No history available.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, - "No information is available.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ITEMS, - "No items.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, - "No netplay hosts found.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, - "No networks found.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, - "No performance counters.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, - "No playlists.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, - "No playlist entries available.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, - "No settings found.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, - "No shader parameters.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OFF, - "OFF") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ON, - "ON") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ONLINE, - "Online") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, - "Online Updater") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, - "Onscreen Display") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, - "Onscreen Overlay") -MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_OVERLAY_SETTINGS, - "Adjust Bezels and Onscreen controls") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, - "Onscreen Notifications") -MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_NOTIFICATIONS_SETTINGS, - "Adjust the Onscreen Notifications") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, - "Browse Archive") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OPTIONAL, - "Optional") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY, - "Overlay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, - "Autoload Preferred Overlay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, - "Overlay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, - "Overlay Opacity") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, - "Overlay Preset") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, - "Overlay Scale") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, - "Onscreen Overlay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, - "Use PAL60 Mode") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, - "Parent directory") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, - "Pause when menu activated") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE, - "Don't run in background") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE, - "Performance Counters") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB, - "Playlists") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, - "Playlist") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, - "Playlists") -MSG_HASH(MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, - "Touch Support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PORT, - "Port") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PRESENT, - "Present") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS, - "Privacy") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIDI_SETTINGS, - "MIDI") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, - "Quit RetroArch") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG, - "Analog supported") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, - "BBFC Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CERO_RATING, - "CERO Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_COOP, - "Co-op supported") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CRC32, - "CRC32") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DESCRIPTION, - "Description") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER, - "Developer") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, - "Edge Magazine Issue") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING, - "Edge Magazine Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_REVIEW, - "Edge Magazine Review") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ELSPA_RATING, - "ELSPA Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, - "Enhancement Hardware") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ESRB_RATING, - "ESRB Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FAMITSU_MAGAZINE_RATING, - "Famitsu Magazine Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE, - "Franchise") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GENRE, - "Genre") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MD5, - "MD5") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME, - "Name") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ORIGIN, - "Origin") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PEGI_RATING, - "PEGI Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, - "Publisher") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, - "Releasedate Month") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, - "Releasedate Year") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RUMBLE, - "Rumble supported") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SERIAL, - "Serial") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1, - "SHA1") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, - "Start Content") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, - "TGDB Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REBOOT, - "Reboot") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, - "Recording Config") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, - "Recording Output") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS, - "Recording") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, - "Load Recording Config...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, - "Record Driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIDI_DRIVER, - "MIDI Driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, - "Enable Recording") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_PATH, - "Save Output Recording as...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, - "Save Recordings in Output Dir") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE, - "Remap File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, - "Load Remap File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, - "Save Core Remap File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CONTENT_DIR, - "Save Content Directory Remap File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, - "Save Game Remap File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE, - "Delete Core Remap File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME, - "Delete Game Remap File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CONTENT_DIR, - "Delete Game Content Directory Remap File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REQUIRED, - "Required") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, - "Restart") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_RETROARCH, - "Restart RetroArch") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RESUME, - "Resume") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, - "Resume") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, - "RetroKeyboard") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD, - "RetroPad") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, - "RetroPad w/ Analog") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, - "Achievements") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_ENABLE, - "Rewind Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_AFTER_TOGGLE, - "Apply After Toggle") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_AFTER_LOAD, - "Auto-Apply Cheats During Game Load") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_GRANULARITY, - "Rewind Granularity") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE, - "Rewind Buffer Size (MB)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE_STEP, - "Rewind Buffer Size Step (MB)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, - "Rewind") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SETTINGS, - "Cheat Settings") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_DETAILS_SETTINGS, - "Cheat Details") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_SETTINGS, - "Start or Continue Cheat Search") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "File Browser") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, - "Config") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, - "Display Start Screen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, - "Right Analog") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, - "Add to Favorites") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES_PLAYLIST, - "Add to Favorites") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RESET_CORE_ASSOCIATION, - "Reset Core Association") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN, - "Run") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_MUSIC, - "Run") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, - "SAMBA Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, - "Savefile") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, - "Save State Auto Index") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, - "Auto Load State") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, - "Auto Save State") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, - "Savestate") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, - "Savestate Thumbnails") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, - "Save Current Configuration") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, - "Save Core Overrides") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, - "Save Content Directory Overrides") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, - "Save Game Overrides") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, - "Save New Configuration") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_STATE, - "Save State") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, - "Saving") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, - "Scan Directory") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_FILE, - "Scan File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, - "Screenshot") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, - "Screen Resolution") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SEARCH, - "Search") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SECONDS, - "seconds") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS, - "Settings") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, - "Settings") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER, - "Shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, - "Apply Changes") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS, - "Shaders") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON, - "Ribbon") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON_SIMPLIFIED, - "Ribbon (simplified)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SIMPLE_SNOW, - "Simple Snow") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOW, - "Snow") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, - "Show Advanced Settings") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, - "Show Hidden Files and Folders") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHUTDOWN, - "Shutdown") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, - "Slow-Motion Ratio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_ENABLED, - "Run-Ahead to Reduce Latency") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_FRAMES, - "Number of Frames to Run Ahead") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_SECONDARY_INSTANCE, - "RunAhead Use Second Instance") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_HIDE_WARNINGS, - "RunAhead Hide Warnings") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, - "Sort Saves In Folders") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, - "Sort Savestates In Folders") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE, - "Write Savestates to Content Dir") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE, - "Write Saves to Content Dir") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, - "System Files are in Content Dir") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, - "Write Screenshots to Content Dir") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SSH_ENABLE, - "SSH Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_START_CORE, - "Start Core") -MSG_HASH(MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD, - "Start Remote RetroPad") -MSG_HASH(MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, - "Start Video Processor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_STATE_SLOT, - "State Slot") -MSG_HASH(MENU_ENUM_LABEL_VALUE_STATUS, - "Status") -MSG_HASH(MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE, - "stdin Commands") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SUPPORTED_CORES, - "Suggested cores") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SUSPEND_SCREENSAVER_ENABLE, - "Suspend Screensaver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE, - "System BGM Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, - "System/BIOS") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, - "System Information") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT, - "7zip support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT, - "ALSA support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_BUILD_DATE, - "Build date") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CG_SUPPORT, - "Cg support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COCOA_SUPPORT, - "Cocoa support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COMMAND_IFACE_SUPPORT, - "Command interface support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CORETEXT_SUPPORT, - "CoreText support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CPU_FEATURES, - "CPU Features") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_DPI, - "Display metric DPI") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT, - "Display metric height (mm)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH, - "Display metric width (mm)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DSOUND_SUPPORT, - "DirectSound support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT, - "WASAPI support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, - "Dynamic library support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, - "Dynamic run-time loading of libretro library") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT, - "EGL support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT, - "OpenGL/Direct3D render-to-texture (multi-pass shaders) support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FFMPEG_SUPPORT, - "FFmpeg support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FREETYPE_SUPPORT, - "FreeType support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER, - "Frontend identifier") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_NAME, - "Frontend name") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_OS, - "Frontend OS") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GIT_VERSION, - "Git version") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GLSL_SUPPORT, - "GLSL support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_HLSL_SUPPORT, - "HLSL support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_JACK_SUPPORT, - "JACK support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_KMS_SUPPORT, - "KMS/EGL support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LAKKA_VERSION, - "Lakka Version") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBRETRODB_SUPPORT, - "LibretroDB support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, - "Libusb support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBXML2_SUPPORT, - "libxml2 XML parsing support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, - "Netplay (peer-to-peer) support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, - "Network Command interface support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_REMOTE_SUPPORT, - "Network Gamepad support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT, - "OpenAL support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT, - "OpenGL ES support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGL_SUPPORT, - "OpenGL support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENSL_SUPPORT, - "OpenSL support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENVG_SUPPORT, - "OpenVG support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OSS_SUPPORT, - "OSS support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OVERLAY_SUPPORT, - "Overlay support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE, - "Power source") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGED, - "Charged") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGING, - "Charging") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_DISCHARGING, - "Discharging") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE, - "No source") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, - "PulseAudio support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PYTHON_SUPPORT, - "Python (script support in shaders) support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RBMP_SUPPORT, - "BMP support (RBMP)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RETRORATING_LEVEL, - "RetroRating level") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RJPEG_SUPPORT, - "JPEG support (RJPEG)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ROARAUDIO_SUPPORT, - "RoarAudio support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RPNG_SUPPORT, - "PNG support (RPNG)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RSOUND_SUPPORT, - "RSound support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RTGA_SUPPORT, - "TGA support (RTGA)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, - "SDL2 support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_IMAGE_SUPPORT, - "SDL image support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_SUPPORT, - "SDL1.2 support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SLANG_SUPPORT, - "Slang support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_THREADING_SUPPORT, - "Threading support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, - "Udev support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, - "Video4Linux2 support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER, - "Video context driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, - "Vulkan support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_METAL_SUPPORT, - "Metal support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT, - "Wayland support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_X11_SUPPORT, - "X11 support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XAUDIO2_SUPPORT, - "XAudio2 support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT, - "XVideo support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT, - "Zlib support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, - "Take Screenshot") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, - "Threaded tasks") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS, - "Thumbnails") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS, - "Left Thumbnails") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_VERTICAL_THUMBNAILS, - "Thumbnails Vertical Disposition") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, - "Thumbnails") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, - "Thumbnails Updater") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, - "Boxarts") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, - "Screenshots") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, - "Title Screens") -MSG_HASH(MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, - "Show date / time") -MSG_HASH(MENU_ENUM_LABEL_VALUE_TITLE_COLOR, - "Menu title color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_TRUE, - "True") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, - "UI Companion Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, - "UI Companion Start On Boot") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_TOGGLE, - "Show desktop menu on startup") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DESKTOP_MENU_ENABLE, - "Enable desktop menu (restart)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, - "Menubar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE, - "Unable to read compressed file.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, - "Undo Load State") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, - "Undo Save State") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UNKNOWN, - "Unknown") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, - "Updater") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, - "Update Assets") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "Update Joypad Profiles") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, - "Update Cg Shaders") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, - "Update Cheats") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, - "Update Core Info Files") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, - "Update Databases") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, - "Update GLSL Shaders") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, - "Update Lakka") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, - "Update Overlays") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_SLANG_SHADERS, - "Update Slang Shaders") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USER, - "User") -MSG_HASH(MENU_ENUM_LABEL_VALUE_KEYBOARD, - "Kbd") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS, - "User Interface") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_LANGUAGE, - "Language") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_SETTINGS, - "User") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Use Builtin Image Viewer") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Use Builtin Media Player") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, - "Allow rotation") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO, - "Config Aspect Ratio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, - "Auto Aspect Ratio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, - "Aspect Ratio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, - "Black Frame Insertion") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, - "Crop Overscan (Reload)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, - "Disable Desktop Composition") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER, - "Video Driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER, - "Video Filter") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, - "Video Filter") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, - "Flicker filter") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, - "Enable Onscreen Notifications") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, - "Notification Font") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, - "Notification Size") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, - "Force aspect ratio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE, - "Force-disable sRGB FBO") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, - "Frame Delay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, - "Start in Fullscreen Mode") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, - "Video Gamma") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, - "Use GPU Recording") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, - "GPU Screenshot Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC, - "Hard GPU Sync") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC_FRAMES, - "Hard GPU Sync Frames") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, - "Max swapchain images") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, - "Notification X Position") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, - "Notification Y Position") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, - "Monitor Index") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, - "Use Post Filter Recording") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, - "Vertical Refresh Rate") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, - "Estimated Screen Framerate") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_POLLED, - "Set Display-Reported Refresh Rate") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ROTATION, - "Rotation") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE, - "Windowed Scale") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, - "Integer Scale") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, - "Video") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, - "Video Shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, - "Shader Passes") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, - "Shader Parameters") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, - "Load Shader Preset") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, - "Save Shader Preset As") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, - "Save Core Preset") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT, - "Save Content Directory Preset") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, - "Save Game Preset") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, - "Enable Hardware Shared Context") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, - "Bilinear Filtering") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, - "Soft Filter Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, - "Vertical Sync (Vsync) Swap Interval") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_TAB, - "Video") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, - "Threaded Video") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, - "Deflicker") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "Custom Aspect Ratio Height") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "Custom Aspect Ratio Width") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, - "Custom Aspect Ratio X Pos.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, - "Custom Aspect Ratio Y Pos.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, - "Set VI Screen Width") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, - "Vertical Sync (Vsync)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, - "Windowed Fullscreen Mode") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, - "Window Width") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, - "Window Height") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_X, - "Fullscreen Width") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_Y, - "Fullscreen Height") -MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, - "Wi-Fi Driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, - "Wi-Fi") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, - "Menu Alpha Factor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_RED, - "Menu Font Red Color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_GREEN, - "Menu Font Green Color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_BLUE, - "Menu Font Blue Color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_FONT, - "Menu Font") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, - "Custom") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, - "FlatUI") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME, - "Monochrome") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME_INVERTED, - "Monochrome Inverted") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_SYSTEMATIC, - "Systematic") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_NEOACTIVE, - "NeoActive") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_PIXEL, - "Pixel") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, - "RetroActive") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROSYSTEM, - "Retrosystem") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, - "Dot-Art") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, - "Menu Color Theme") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_APPLE_GREEN, - "Apple Green") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK, - "Dark") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LIGHT, - "Light") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MORNING_BLUE, - "Morning Blue") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK_PURPLE, - "Dark Purple") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ELECTRIC_BLUE, - "Electric Blue") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GOLDEN, - "Golden") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LEGACY_RED, - "Legacy Red") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDNIGHT_BLUE, - "Midnight Blue") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_PLAIN, - "Plain") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, - "Undersea") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, - "Volcanic Red") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, - "Menu Shader Pipeline") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, - "Menu Scale Factor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, - "Icon Shadows Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_HISTORY, - "Show History Tab") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, - "Show Import content Tab") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, - "Show Playlist Tabs") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_FAVORITES, - "Show Favorites Tab") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_IMAGES, - "Show Image Tab") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_MUSIC, - "Show Music Tab") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS, - "Show Settings Tab") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO, - "Show Video Tab") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, - "Show Netplay Tab") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_LAYOUT, - "Menu Layout") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_THEME, - "Menu Icon Theme") -MSG_HASH(MENU_ENUM_LABEL_VALUE_YES, - "Yes") -MSG_HASH(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, - "Shader Preset") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, - "Enable or disable achievements. For more information, visit http://retroachievements.org") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, - "Enable or disable unofficial achievements and/or beta features for testing purposes.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, - "Enable or disable savestates, cheats, rewind, pause, and slow-motion for all games.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_LEADERBOARDS_ENABLE, - "Enable or disable in-game leaderboards. Has no effect if Hardcore Mode is disabled.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_BADGES_ENABLE, - "Enable or disable badge display in the Achievement List.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE, - "Enable or disable OSD verbosity for achievements.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_AUTO_SCREENSHOT, - "Automatically take a screenshot when an achievement is triggered.") -MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, - "Change drivers used by the system.") -MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "Change achievement settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_SETTINGS, - "Change core settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, - "Change recording settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, - "Change display overlay and keyboard overlay, and onscreen notification settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, - "Change rewind, fast-forward, and slow-motion settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVING_SETTINGS, - "Change saving settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, - "Change logging settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, - "Change user interface settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_USER_SETTINGS, - "Change account, username, and language settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, - "Change your privacy settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIDI_SETTINGS, - "Change MIDI settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, - "Change default directories where files are located.") -MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, - "Change playlist settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, - "Configure server and network settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, - "Scan content and add to the database.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, - "Change audio output settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, - "Enable or disable bluetooth.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, - "Saves changes to the configuration file on exit.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, - "Change default settings for configuration files.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, - "Manage and create configuration files.") -MSG_HASH(MENU_ENUM_SUBLABEL_CPU_CORES, - "Amount of cores that the CPU has.") -MSG_HASH(MENU_ENUM_SUBLABEL_FPS_SHOW, - "Displays the current framerate per second onscreen.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, - "Configure hotkey settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Gamepad button combination to toggle menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_SETTINGS, - "Change joypad, keyboard, and mouse settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, - "Configure controls for this user.") -MSG_HASH(MENU_ENUM_SUBLABEL_LATENCY_SETTINGS, - "Change settings related to video, audio and input latency.") -MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, - "Enable or disable logging to the terminal.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, - "Join or host a netplay session.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, - "Search for and connect to netplay hosts on the local network.") -MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Display system information.") -MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, - "Download add-ons, components, and content for RetroArch.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, - "Enable or disable network sharing of your folders.") -MSG_HASH(MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, - "Manage operating system level services.") -MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, - "Show hidden files/directories inside the file browser.") -MSG_HASH(MENU_ENUM_SUBLABEL_SSH_ENABLE, - "Enable or disable remote command line access.") -MSG_HASH(MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, - "Prevents your system's screensaver from becoming active.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, - "Sets the window size relative to the core viewport size. Alternatively, you can set a window width and height below for a fixed window size.") -MSG_HASH(MENU_ENUM_SUBLABEL_USER_LANGUAGE, - "Sets the language of the interface.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Inserts a black frame inbetween frames. Useful for users with 120Hz screens who want to play 60Hz content to eliminate ghosting.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, - "Reduces latency at the cost of a higher risk of video stuttering. Adds a delay after V-Sync (in ms).") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, - "Sets how many frames the CPU can run ahead of the GPU when using 'Hard GPU Sync'.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, - "Tells the video driver to explicitly use a specified buffering mode.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, - "Selects which display screen to use.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, - "The accurate estimated refresh rate of the screen in Hz.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_POLLED, - "The refresh rate as reported by the display driver.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, - "Change video output settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_WIFI_SETTINGS, - "Scans for wireless networks and establishes connection.") -MSG_HASH(MENU_ENUM_SUBLABEL_HELP_LIST, - "Learn more about how the program works.") -MSG_HASH(MSG_ADDED_TO_FAVORITES, - "Added to favorites") -MSG_HASH(MSG_RESET_CORE_ASSOCIATION, - "Playlist entry core association has been reset.") -MSG_HASH(MSG_APPENDED_DISK, - "Appended disk") -MSG_HASH(MSG_APPLICATION_DIR, - "Application Dir") -MSG_HASH(MSG_APPLYING_CHEAT, - "Applying cheat changes.") -MSG_HASH(MSG_APPLYING_SHADER, - "Applying shader") -MSG_HASH(MSG_AUDIO_MUTED, - "Audio muted.") -MSG_HASH(MSG_AUDIO_UNMUTED, - "Audio unmuted.") -MSG_HASH(MSG_AUTOCONFIG_FILE_ERROR_SAVING, - "Error saving autoconf file.") -MSG_HASH(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, - "Autoconfig file saved successfully.") -MSG_HASH(MSG_AUTOSAVE_FAILED, - "Could not initialize autosave.") -MSG_HASH(MSG_AUTO_SAVE_STATE_TO, - "Auto save state to") -MSG_HASH(MSG_BLOCKING_SRAM_OVERWRITE, - "Blocking SRAM Overwrite") -MSG_HASH(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, - "Bringing up command interface on port") -MSG_HASH(MSG_BYTES, - "bytes") -MSG_HASH(MSG_CANNOT_INFER_NEW_CONFIG_PATH, - "Cannot infer new config path. Use current time.") -MSG_HASH(MSG_CHEEVOS_HARDCORE_MODE_ENABLE, - "Hardcore Mode Enabled, savestate & rewind were disabled.") -MSG_HASH(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, - "Comparing with known magic numbers...") -MSG_HASH(MSG_COMPILED_AGAINST_API, - "Compiled against API") -MSG_HASH(MSG_CONFIG_DIRECTORY_NOT_SET, - "Config directory not set. Cannot save new config.") -MSG_HASH(MSG_CONNECTED_TO, - "Connected to") -MSG_HASH(MSG_CONTENT_CRC32S_DIFFER, - "Content CRC32s differ. Cannot use different games.") -MSG_HASH(MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, - "Content loading skipped. Implementation will load it on its own.") -MSG_HASH(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "Core does not support save states.") -MSG_HASH(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, - "Core options file created successfully.") -MSG_HASH(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, - "Could not find any next driver") -MSG_HASH(MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, - "Could not find compatible system.") -MSG_HASH(MSG_COULD_NOT_FIND_VALID_DATA_TRACK, - "Could not find valid data track") -MSG_HASH(MSG_COULD_NOT_OPEN_DATA_TRACK, - "could not open data track") -MSG_HASH(MSG_COULD_NOT_READ_CONTENT_FILE, - "Could not read content file") -MSG_HASH(MSG_COULD_NOT_READ_MOVIE_HEADER, - "Could not read movie header.") -MSG_HASH(MSG_COULD_NOT_READ_STATE_FROM_MOVIE, - "Could not read state from movie.") -MSG_HASH(MSG_CRC32_CHECKSUM_MISMATCH, - "CRC32 checksum mismatch between content file and saved content checksum in replay file header. Replay highly likely to desync on playback.") -MSG_HASH(MSG_CUSTOM_TIMING_GIVEN, - "Custom timing given") -MSG_HASH(MSG_DECOMPRESSION_ALREADY_IN_PROGRESS, - "Decompression already in progress.") -MSG_HASH(MSG_DECOMPRESSION_FAILED, - "Decompression failed.") -MSG_HASH(MSG_DETECTED_VIEWPORT_OF, - "Detected viewport of") -MSG_HASH(MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, - "Did not find a valid content patch.") -MSG_HASH(MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, - "Disconnect device from a valid port.") -MSG_HASH(MSG_DISK_CLOSED, - "Closed") -MSG_HASH(MSG_DISK_EJECTED, - "Ejected") -MSG_HASH(MSG_DOWNLOADING, - "Downloading") -MSG_HASH(MSG_INDEX_FILE, - "index") -MSG_HASH(MSG_DOWNLOAD_FAILED, - "Download failed") -MSG_HASH(MSG_ERROR, - "Error") -MSG_HASH(MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, - "Libretro core requires content, but nothing was provided.") -MSG_HASH(MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT, - "Libretro core requires special content, but none were provided.") -MSG_HASH(MSG_ERROR_PARSING_ARGUMENTS, - "Error parsing arguments.") -MSG_HASH(MSG_ERROR_SAVING_CORE_OPTIONS_FILE, - "Error saving core options file.") -MSG_HASH(MSG_ERROR_SAVING_REMAP_FILE, - "Error saving remap file.") -MSG_HASH(MSG_ERROR_REMOVING_REMAP_FILE, - "Error removing remap file.") -MSG_HASH(MSG_ERROR_SAVING_SHADER_PRESET, - "Error saving shader preset.") -MSG_HASH(MSG_EXTERNAL_APPLICATION_DIR, - "External Application Dir") -MSG_HASH(MSG_EXTRACTING, - "Extracting") -MSG_HASH(MSG_EXTRACTING_FILE, - "Extracting file") -MSG_HASH(MSG_FAILED_SAVING_CONFIG_TO, - "Failed saving config to") -MSG_HASH(MSG_FAILED_TO, - "Failed to") -MSG_HASH(MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, - "Failed to accept incoming spectator.") -MSG_HASH(MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, - "Failed to allocate memory for patched content...") -MSG_HASH(MSG_FAILED_TO_APPLY_SHADER, - "Failed to apply shader.") -MSG_HASH(MSG_FAILED_TO_BIND_SOCKET, - "Failed to bind socket.") -MSG_HASH(MSG_FAILED_TO_CREATE_THE_DIRECTORY, - "Failed to create the directory.") -MSG_HASH(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, - "Failed to extract content from compressed file") -MSG_HASH(MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, - "Failed to get nickname from client.") -MSG_HASH(MSG_FAILED_TO_LOAD, - "Failed to load") -MSG_HASH(MSG_FAILED_TO_LOAD_CONTENT, - "Failed to load content") -MSG_HASH(MSG_FAILED_TO_LOAD_MOVIE_FILE, - "Failed to load movie file") -MSG_HASH(MSG_FAILED_TO_LOAD_OVERLAY, - "Failed to load overlay.") -MSG_HASH(MSG_FAILED_TO_LOAD_STATE, - "Failed to load state from") -MSG_HASH(MSG_FAILED_TO_OPEN_LIBRETRO_CORE, - "Failed to open libretro core") -MSG_HASH(MSG_FAILED_TO_PATCH, - "Failed to patch") -MSG_HASH(MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT, - "Failed to receive header from client.") -MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME, - "Failed to receive nickname.") -MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST, - "Failed to receive nickname from host.") -MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_SIZE_FROM_HOST, - "Failed to receive nickname size from host.") -MSG_HASH(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST, - "Failed to receive SRAM data from host.") -MSG_HASH(MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY, - "Failed to remove disk from tray.") -MSG_HASH(MSG_FAILED_TO_REMOVE_TEMPORARY_FILE, - "Failed to remove temporary file") -MSG_HASH(MSG_FAILED_TO_SAVE_SRAM, - "Failed to save SRAM") -MSG_HASH(MSG_FAILED_TO_SAVE_STATE_TO, - "Failed to save state to") -MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME, - "Failed to send nickname.") -MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_SIZE, - "Failed to send nickname size.") -MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT, - "Failed to send nickname to client.") -MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, - "Failed to send nickname to host.") -MSG_HASH(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, - "Failed to send SRAM data to client.") -MSG_HASH(MSG_FAILED_TO_START_AUDIO_DRIVER, - "Failed to start audio driver. Will continue without audio.") -MSG_HASH(MSG_FAILED_TO_START_MOVIE_RECORD, - "Failed to start movie record.") -MSG_HASH(MSG_FAILED_TO_START_RECORDING, - "Failed to start recording.") -MSG_HASH(MSG_FAILED_TO_TAKE_SCREENSHOT, - "Failed to take screenshot.") -MSG_HASH(MSG_FAILED_TO_UNDO_LOAD_STATE, - "Failed to undo load state.") -MSG_HASH(MSG_FAILED_TO_UNDO_SAVE_STATE, - "Failed to undo save state.") -MSG_HASH(MSG_FAILED_TO_UNMUTE_AUDIO, - "Failed to unmute audio.") -MSG_HASH(MSG_FATAL_ERROR_RECEIVED_IN, - "Fatal error received in") -MSG_HASH(MSG_FILE_NOT_FOUND, - "File not found") -MSG_HASH(MSG_FOUND_AUTO_SAVESTATE_IN, - "Found auto savestate in") -MSG_HASH(MSG_FOUND_DISK_LABEL, - "Found disk label") -MSG_HASH(MSG_FOUND_FIRST_DATA_TRACK_ON_FILE, - "Found first data track on file") -MSG_HASH(MSG_FOUND_LAST_STATE_SLOT, - "Found last state slot") -MSG_HASH(MSG_FOUND_SHADER, - "Found shader") -MSG_HASH(MSG_FRAMES, - "Frames") -MSG_HASH(MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT, - "Per-Game Options: game-specific core options found at") -MSG_HASH(MSG_GOT_INVALID_DISK_INDEX, - "Got invalid disk index.") -MSG_HASH(MSG_GRAB_MOUSE_STATE, - "Grab mouse state") -MSG_HASH(MSG_GAME_FOCUS_ON, - "Game focus on") -MSG_HASH(MSG_GAME_FOCUS_OFF, - "Game focus off") -MSG_HASH(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, - "Libretro core is hardware rendered. Must use post-shaded recording as well.") -MSG_HASH(MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, - "Inflated checksum did not match CRC32.") -MSG_HASH(MSG_INPUT_CHEAT, - "Input Cheat") -MSG_HASH(MSG_INPUT_CHEAT_FILENAME, - "Input Cheat Filename") -MSG_HASH(MSG_INPUT_PRESET_FILENAME, - "Input Preset Filename") -MSG_HASH(MSG_INPUT_RENAME_ENTRY, - "Rename Title") -MSG_HASH(MSG_INTERFACE, - "Interface") -MSG_HASH(MSG_INTERNAL_STORAGE, - "Internal Storage") -MSG_HASH(MSG_REMOVABLE_STORAGE, - "Removable Storage") -MSG_HASH(MSG_INVALID_NICKNAME_SIZE, - "Invalid nickname size.") -MSG_HASH(MSG_IN_BYTES, - "in bytes") -MSG_HASH(MSG_IN_GIGABYTES, - "in gigabytes") -MSG_HASH(MSG_IN_MEGABYTES, - "in megabytes") -MSG_HASH(MSG_LIBRETRO_ABI_BREAK, - "is compiled against a different version of libretro than this libretro implementation.") -MSG_HASH(MSG_LIBRETRO_FRONTEND, - "Frontend for libretro") -MSG_HASH(MSG_LOADED_STATE_FROM_SLOT, - "Loaded state from slot #%d.") -MSG_HASH(MSG_LOADED_STATE_FROM_SLOT_AUTO, - "Loaded state from slot #-1 (auto).") -MSG_HASH(MSG_LOADING, - "Loading") -MSG_HASH(MSG_FIRMWARE, - "One or more firmware files are missing") -MSG_HASH(MSG_LOADING_CONTENT_FILE, - "Loading content file") -MSG_HASH(MSG_LOADING_HISTORY_FILE, - "Loading history file") -MSG_HASH(MSG_LOADING_STATE, - "Loading state") -MSG_HASH(MSG_MEMORY, - "Memory") -MSG_HASH(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, - "Movie file is not a valid BSV1 file.") -MSG_HASH(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, - "Movie format seems to have a different serializer version. Will most likely fail.") -MSG_HASH(MSG_MOVIE_PLAYBACK_ENDED, - "Movie playback ended.") -MSG_HASH(MSG_MOVIE_RECORD_STOPPED, - "Stopping movie record.") -MSG_HASH(MSG_NETPLAY_FAILED, - "Failed to initialize netplay.") -MSG_HASH(MSG_NO_CONTENT_STARTING_DUMMY_CORE, - "No content, starting dummy core.") -MSG_HASH(MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, - "No save state has been overwritten yet.") -MSG_HASH(MSG_NO_STATE_HAS_BEEN_LOADED_YET, - "No state has been loaded yet.") -MSG_HASH(MSG_OVERRIDES_ERROR_SAVING, - "Error saving overrides.") -MSG_HASH(MSG_OVERRIDES_SAVED_SUCCESSFULLY, - "Overrides saved successfully.") -MSG_HASH(MSG_PAUSED, - "Paused.") -MSG_HASH(MSG_PROGRAM, - "RetroArch") -MSG_HASH(MSG_READING_FIRST_DATA_TRACK, - "Reading first data track...") -MSG_HASH(MSG_RECEIVED, - "received") -MSG_HASH(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, - "Recording terminated due to resize.") -MSG_HASH(MSG_RECORDING_TO, - "Recording to") -MSG_HASH(MSG_REDIRECTING_CHEATFILE_TO, - "Redirecting cheat file to") -MSG_HASH(MSG_REDIRECTING_SAVEFILE_TO, - "Redirecting save file to") -MSG_HASH(MSG_REDIRECTING_SAVESTATE_TO, - "Redirecting savestate to") -MSG_HASH(MSG_REMAP_FILE_SAVED_SUCCESSFULLY, - "Remap file saved successfully.") -MSG_HASH(MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, - "Remap file removed successfully.") -MSG_HASH(MSG_REMOVED_DISK_FROM_TRAY, - "Removed disk from tray.") -MSG_HASH(MSG_REMOVING_TEMPORARY_CONTENT_FILE, - "Removing temporary content file") -MSG_HASH(MSG_RESET, - "Reset") -MSG_HASH(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT, - "Restarting recording due to driver reinit.") -MSG_HASH(MSG_RESTORED_OLD_SAVE_STATE, - "Restored old save state.") -MSG_HASH(MSG_RESTORING_DEFAULT_SHADER_PRESET_TO, - "Shaders: restoring default shader preset to") -MSG_HASH(MSG_REVERTING_SAVEFILE_DIRECTORY_TO, - "Reverting savefile directory to") -MSG_HASH(MSG_REVERTING_SAVESTATE_DIRECTORY_TO, - "Reverting savestate directory to") -MSG_HASH(MSG_REWINDING, - "Rewinding.") -MSG_HASH(MSG_REWIND_INIT, - "Initializing rewind buffer with size") -MSG_HASH(MSG_REWIND_INIT_FAILED, - "Failed to initialize rewind buffer. Rewinding will be disabled.") -MSG_HASH(MSG_REWIND_INIT_FAILED_THREADED_AUDIO, - "Implementation uses threaded audio. Cannot use rewind.") -MSG_HASH(MSG_REWIND_REACHED_END, - "Reached end of rewind buffer.") -MSG_HASH(MSG_SAVED_NEW_CONFIG_TO, - "Saved new config to") -MSG_HASH(MSG_SAVED_STATE_TO_SLOT, - "Saved state to slot #%d.") -MSG_HASH(MSG_SAVED_STATE_TO_SLOT_AUTO, - "Saved state to slot #-1 (auto).") -MSG_HASH(MSG_SAVED_SUCCESSFULLY_TO, - "Saved successfully to") -MSG_HASH(MSG_SAVING_RAM_TYPE, - "Saving RAM type") -MSG_HASH(MSG_SAVING_STATE, - "Saving state") -MSG_HASH(MSG_SCANNING, - "Scanning") -MSG_HASH(MSG_SCANNING_OF_DIRECTORY_FINISHED, - "Scanning of directory finished") -MSG_HASH(MSG_SENDING_COMMAND, - "Sending command") -MSG_HASH(MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED, - "Several patches are explicitly defined, ignoring all...") -MSG_HASH(MSG_SHADER, - "Shader") -MSG_HASH(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, - "Shader preset saved successfully.") -MSG_HASH(MSG_SKIPPING_SRAM_LOAD, - "Skipping SRAM load.") -MSG_HASH(MSG_SLOW_MOTION, - "Slow motion.") -MSG_HASH(MSG_FAST_FORWARD, - "Fast forward.") -MSG_HASH(MSG_SLOW_MOTION_REWIND, - "Slow motion rewind.") -MSG_HASH(MSG_SRAM_WILL_NOT_BE_SAVED, - "SRAM will not be saved.") -MSG_HASH(MSG_STARTING_MOVIE_PLAYBACK, - "Starting movie playback.") -MSG_HASH(MSG_STARTING_MOVIE_RECORD_TO, - "Starting movie record to") -MSG_HASH(MSG_STATE_SIZE, - "State size") -MSG_HASH(MSG_STATE_SLOT, - "State slot") -MSG_HASH(MSG_TAKING_SCREENSHOT, - "Taking screenshot.") -MSG_HASH(MSG_TO, - "to") -MSG_HASH(MSG_UNDID_LOAD_STATE, - "Undid load state.") -MSG_HASH(MSG_UNDOING_SAVE_STATE, - "Undoing save state") -MSG_HASH(MSG_UNKNOWN, - "Unknown") -MSG_HASH(MSG_UNPAUSED, - "Unpaused.") -MSG_HASH(MSG_UNRECOGNIZED_COMMAND, - "Unrecognized command") -MSG_HASH(MSG_USING_CORE_NAME_FOR_NEW_CONFIG, - "Using core name for new config.") -MSG_HASH(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, - "Using libretro dummy core. Skipping recording.") -MSG_HASH(MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, - "Connect device from a valid port.") -MSG_HASH(MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, - "Disconnecting device from port") -MSG_HASH(MSG_VALUE_REBOOTING, - "Rebooting...") -MSG_HASH(MSG_VALUE_SHUTTING_DOWN, - "Shutting down...") -MSG_HASH(MSG_VERSION_OF_LIBRETRO_API, - "Version of libretro API") -MSG_HASH(MSG_VIEWPORT_SIZE_CALCULATION_FAILED, - "Viewport size calculation failed! Will continue using raw data. This will probably not work right ...") -MSG_HASH(MSG_VIRTUAL_DISK_TRAY, - "virtual disk tray.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_LATENCY, - "Desired audio latency in milliseconds. Might not be honored if the audio driver can't provide given latency.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MUTE, - "Mute/unmute audio.") -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, - "Helps smooth out imperfections in timing when synchronizing audio and video. Be aware that if disabled, proper synchronization is nearly impossible to obtain." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CAMERA_ALLOW, - "Allow or disallow camera access by cores." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LOCATION_ALLOW, - "Allow or disallow location services access by cores." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, - "Maximum amount of users supported by RetroArch." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, - "Influence how input polling is done inside RetroArch. Setting it to 'Early' or 'Late' can result in less latency, depending on your configuration." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, - "Allows any user to control the menu. If disabled, only User 1 can control the menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_VOLUME, - "Audio volume (in dB). 0 dB is normal volume, and no gain is applied." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_WASAPI_EXCLUSIVE_MODE, - "Allow the WASAPI driver to take exclusive control of the audio device. If disabled, it will use shared mode instead." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_WASAPI_FLOAT_FORMAT, - "Use float format for the WASAPI driver, if supported by your audio device." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH, - "The intermediate buffer length (in frames) when using the WASAPI driver in shared mode." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_SYNC, - "Synchronize audio. Recommended." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, - "How far an axis must be tilted to result in a button press." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, - "Amount of seconds to wait until proceeding to the next bind." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_BIND_HOLD, - "Amount of seconds to hold an input to bind it." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Describes the period when turbo-enabled buttons are toggled. Numbers are described in frames." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Describes how long the period of a turbo-enabled button should be. Numbers are described in frames." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VSYNC, - "Synchronizes the output video of the graphics card to the refresh rate of the screen. Recommended." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, - "Allow cores to set rotation. When disabled, rotation requests are ignored. Useful for setups where one manually rotates the screen." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN, - "Some cores might have a shutdown feature. If enabled, it will prevent the core from shutting RetroArch down. Instead, it loads a dummy core." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, - "Check if all the required firmware is present before attempting to load content." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, - "Vertical refresh rate of your screen. Used to calculate a suitable audio input rate. NOTE: This will be ignored if 'Threaded Video' is enabled." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_ENABLE, - "Enable audio output." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, - "The maximum change in audio input rate. Increasing this enables very large changes in timing at the cost of an inaccurate audio pitch (e.g., running PAL cores on NTSC displays)." - ) -MSG_HASH( - MSG_FAILED, - "failed" - ) -MSG_HASH( - MSG_SUCCEEDED, - "succeeded" - ) -MSG_HASH( - MSG_DEVICE_NOT_CONFIGURED, - "not configured" - ) -MSG_HASH( - MSG_DEVICE_NOT_CONFIGURED_FALLBACK, - "not configured, using fallback" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, - "Database Cursor List" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DEVELOPER, - "Database - Filter : Developer" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PUBLISHER, - "Database - Filter : Publisher" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISABLED, - "Disabled" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ENABLED, - "Enabled" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_PATH, - "Content History Path" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ORIGIN, - "Database - Filter : Origin") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_FRANCHISE, - "Database - Filter : Franchise") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ESRB_RATING, - "Database - Filter : ESRB Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ELSPA_RATING, - "Database - Filter : ELSPA Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PEGI_RATING, - "Database - Filter : PEGI Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_CERO_RATING, - "Database - Filter : CERO Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_BBFC_RATING, - "Database - Filter : BBFC Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_MAX_USERS, - "Database - Filter : Max Users") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_MONTH, - "Database - Filter : Releasedate By Month") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_YEAR, - "Database - Filter : Releasedate By Year") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, - "Database - Filter : Edge Magazine Issue") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, - "Database - Filter : Edge Magazine Rating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, - "Database Info") -MSG_HASH(MSG_WIFI_SCAN_COMPLETE, - "Wi-Fi scan complete.") -MSG_HASH(MSG_SCANNING_WIRELESS_NETWORKS, - "Scanning wireless networks...") -MSG_HASH(MSG_NETPLAY_LAN_SCAN_COMPLETE, - "Netplay scan complete.") -MSG_HASH(MSG_NETPLAY_LAN_SCANNING, - "Scanning for netplay hosts...") -MSG_HASH(MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, - "Pause gameplay when RetroArch is not the active window.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, - "Enable or disable composition.") -MSG_HASH(MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, - "Enable or disable recent playlist for games, images, music, and videos.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, - "Limit the number of entries in recent playlist for games, images, music, and videos.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, - "Unified Menu Controls") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, - "Use the same controls for both the menu and the game. Applies to the keyboard.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, - "Show onscreen messages.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, - "User %d Remote Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, - "Show battery level") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FILE, - "Select File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FROM_COLLECTION, - "Select From Collection") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER, - "Filter") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCALE, - "Scale") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, - "Netplay will start when content is loaded.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, - "Couldn't find a suitable core or content file, load manually.") -MSG_HASH( - MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, - "Browse URL" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_BROWSE_URL, - "URL Path" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_BROWSE_START, - "Start" - ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, - "Bokeh") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOWFLAKE, - "Snowflake") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, - "Refresh Room List") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, - "Nickname: %s") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, - "Nickname (lan): %s") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, - "Compatible content found") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, - "Cuts off a few pixels around the edges of the image customarily left blank by developers which sometimes also contain garbage pixels.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, - "Adds a slight blur to the image to take the edge off of the hard pixel edges. This option has very little impact on performance.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FILTER, - "Apply a CPU-powered video filter. NOTE: Might come at a high performance cost. Some video filters might only work for cores that use 32bit or 16bit color.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, - "Input the username of your RetroAchievements account.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, - "Input the password of your RetroAchievements account.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, - "Input your user name here. This will be used for netplay sessions, among other things.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, - "Capture the image after filters (but not shaders) are applied. Your video will look as fancy as what you see on your screen.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_LIST, - "Select which core to use.") -MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, - "Select which content to start.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, - "Show network interface(s) and associated IP addresses.") -MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, - "Show information specific to the device.") -MSG_HASH(MENU_ENUM_SUBLABEL_QUIT_RETROARCH, - "Quit the program.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, - "Set the custom width size for the display window. Leaving it at 0 will attempt to scale the window as large as possible.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, - "Set the custom height size for the display window. Leaving it at 0 will attempt to scale the window as large as possible.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, - "Set the custom width size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, - "Set the custom height size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, - "Specify custom X axis position for onscreen text.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, - "Specify custom Y axis position for onscreen text.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Specify the font size in points.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, - "Hide the overlay while inside the menu, and show it again when exiting the menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, - "Show keyboard/controller inputs on the onscreen overlay.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, - "Select the port for the overlay to listen to if Show Inputs On Overlay is enabled.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, - "Scanned content will appear here." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, - "Only scales video in integer steps. The base size depends on system-reported geometry and aspect ratio. If 'Force Aspect' is not set, X/Y will be integer scaled independently." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_GPU_SCREENSHOT, - "Screenshots output of GPU shaded material if available." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_ROTATION, - "Forces a certain rotation of the screen. The rotation is added to rotations which the core sets." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FORCE_SRGB_DISABLE, - "Forcibly disable sRGB FBO support. Some Intel OpenGL drivers on Windows have video problems with sRGB FBO support if this is enabled. Enabling this can work around it." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN, - "Start in fullscreen. Can be changed at runtime. Can be overridden by a command line switch" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_WINDOWED_FULLSCREEN, - "If fullscreen, prefer using a windowed fullscreen mode." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_GPU_RECORD, - "Records output of GPU shaded material if available." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, - "When making a savestate, save state index is automatically increased before it is saved. When loading content, the index will be set to the highest existing index." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, - "Block Save RAM from being overwritten when loading save states. Might potentially lead to buggy games." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_FASTFORWARD_RATIO, - "The maximum rate at which content will be run when using fast forward (e.g., 5.0x for 60 fps content = 300 fps cap). If set to 0.0x, fastforward ratio is unlimited (no FPS cap)." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, - "When in slow motion, content will slow down by the factor specified/set." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_ENABLED, - "Run core logic one or more frames ahead then load the state back to reduce perceived input lag." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_FRAMES, - "The number of frames to run ahead. Causes gameplay issues such as jitter if you exceed the number of lag frames internal to the game." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_SECONDARY_INSTANCE, - "Use a second instance of the RetroArch core to run ahead. Prevents audio problems due to loading state." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS, - "Hides the warning message that appears when using RunAhead and the core does not support savestates." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_REWIND_ENABLE, - "Enable rewinding. This will take a performance hit when playing." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_TOGGLE, - "Apply cheat immediately after toggling." + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD_APPEND, + "Load Cheat File (Append)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, + "Save Cheat File As" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, + "Cheat Passes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, + "Description" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, + "Hardcore Mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_LEADERBOARDS_ENABLE, + "Leaderboards" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_BADGES_ENABLE, + "Achievement Badges" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, + "Locked Achievements:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY, + "Locked" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_SETTINGS, + "RetroAchievements" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, + "Test Unofficial Achievements" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, + "Unlocked Achievements:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY, + "Unlocked" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, + "Hardcore" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VERBOSE_ENABLE, + "Verbose Mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_AUTO_SCREENSHOT, + "Automatic Screenshot" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, + "Close Content" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIG, + "Config" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, + "Load Configuration" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, + "Configuration" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, + "Save Configuration on Exit" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST, + "Collections" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, + "Database" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_DIR, + "Content" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, + "History List Size" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, + "Allow to remove entries" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, + "Quick Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, + "Downloads" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, + "Downloads" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, + "Cheats" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, + "Core Counters" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_ENABLE, + "Show core name" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, + "Core Information" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, + "Authors" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, + "Categories" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL, + "Core label" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME, + "Core name" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, + "Firmware(s)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, + "License(s)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, + "Permissions" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS, + "Supported extensions" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_MANUFACTURER, + "System manufacturer" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, + "System name" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, + "Controls" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST, + "Load Core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, + "Options" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_SETTINGS, + "Core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_SET_SUPPORTS_NO_CONTENT_ENABLE, + "Start a Core Automatically" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Automatically extract downloaded archive" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, + "Buildbot Cores URL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST, + "Core Updater" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, + "Updater" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CPU_ARCHITECTURE, + "CPU Architecture:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CPU_CORES, + "CPU Cores:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CURSOR_DIRECTORY, + "Cursor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CURSOR_MANAGER, + "Cursor Manager" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO, + "Custom Ratio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER, + "Database Manager" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_SELECTION, + "Database Selection" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DELETE_ENTRY, + "Remove" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FAVORITES, + "Start directory" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, + "Directory not found." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS, + "Directory" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS, + "Disk Cycle Tray Status" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, + "Disk Image Append" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISK_INDEX, + "Disk Index" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, + "Disk Control" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DONT_CARE, + "Don't care" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, + "Downloads" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE, + "Download Core..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT, + "Content Downloader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_ENABLE, + "DPI Override Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_VALUE, + "DPI Override" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, + "Driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, + "Load Dummy on Core Shutdown" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, + "Check for Missing Firmware Before Loading" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, + "Dynamic Background" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, + "Dynamic Backgrounds" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, + "Enable Achievements" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, + "Menu entry hover color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, + "Menu entry normal color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FALSE, + "False" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, + "Maximum Run Speed" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, + "Favorites" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FPS_SHOW, + "Display Framerate" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, + "Limit Maximum Run Speed" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VRR_RUNLOOP_ENABLE, + "Sync to Exact Content Framerate (G-Sync, FreeSync)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, + "Frame Throttle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, + "Frontend Counters" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, + "Load Content-Specific Core Options Automatically" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, + "Create game-options file" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, + "Save Game-options file" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP, + "Help" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, + "Audio/Video Troubleshooting" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, + "Changing Virtual Gamepad Overlay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, + "Basic Menu Controls" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_LIST, + "Help" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, + "Loading Content" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, + "Scanning For Content" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, + "What Is A Core?" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, + "History List Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HISTORY_TAB, + "History" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, + "Horizontal Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_IMAGES_TAB, + "Image" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INFORMATION, + "Information" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, + "Information" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, + "Analog To Digital Type" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, + "All Users Control Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, + "Left Analog X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, + "Left analog X- (left)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, + "Left analog X+ (right)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y, + "Left Analog Y" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, + "Left analog Y- (up)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, + "Left analog Y+ (down)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X, + "Right Analog X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, + "Right analog X- (left)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, + "Right analog X+ (right)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y, + "Right Analog Y" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, + "Right analog Y- (up)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, + "Right analog Y+ (down)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, + "Gun Trigger" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, + "Gun Reload" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A, + "Gun Aux A" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B, + "Gun Aux B" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C, + "Gun Aux C" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START, + "Gun Start" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT, + "Gun Select" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP, + "Gun D-pad Up" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN, + "Gun D-pad Down" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT, + "Gun D-pad Left" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, + "Gun D-pad Right" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, + "Autoconfig Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, + "Analog Stick Deadzone" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, + "Menu Swap OK & Cancel Buttons" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, + "Bind All" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, + "Bind Default All" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_BIND_TIMEOUT, + "Bind Timeout" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_BIND_HOLD, + "Bind Hold" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_HIDE_UNBOUND, + "Hide Unbound Core Input Descriptors" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW, + "Display Input Descriptor Labels" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, + "Device Index" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, + "Device Type" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, + "Mouse Index" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DRIVER, + "Input Driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + "Duty Cycle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, + "Input Hotkey Binds" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, + "Keyboard Gamepad Mapping Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, + "A button (right)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, + "B button (down)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, + "Down D-pad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, + "L2 button (trigger)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, + "L3 button (thumb)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, + "L button (shoulder)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, + "Left D-pad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, + "R2 button (trigger)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, + "R3 button (thumb)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, + "R button (shoulder)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, + "Right D-pad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, + "Select button" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, + "Start button" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, + "Up D-pad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, + "X button (top)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, + "Y button (left)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_KEY, + "(Key: %s)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_LEFT, + "Mouse 1" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_RIGHT, + "Mouse 2" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_MIDDLE, + "Mouse 3" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON4, + "Mouse 4" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON5, + "Mouse 5" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_UP, + "Wheel Up" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_DOWN, + "Wheel Down" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_UP, + "Wheel Left" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_DOWN, + "Wheel Right" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, + "Keyboard Gamepad Mapping Type" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, + "Max Users" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, + "Menu Toggle Gamepad Combo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, + "Cheat index -" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, + "Cheat index +" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, + "Cheat toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, + "Disk eject toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, + "Disk next" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, + "Disk prev" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, + "Enable hotkeys" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, + "Fast forward hold" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, + "Fast forward toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, + "Frameadvance" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, + "Fullscreen toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, + "Grab mouse toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, + "Game focus toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, + "Desktop menu toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, + "Load state" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, + "Menu toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, + "Movie record toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, + "Audio mute toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, + "Netplay toggle play/spectate mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, + "On-screen keyboard toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, + "Overlay next" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, + "Pause toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, + "Quit RetroArch" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, + "Reset game" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, + "Rewind" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_DETAILS, + "Cheat Details" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_SEARCH, + "Start or Continue Cheat Search" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, + "Save state" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, + "Take screenshot" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, + "Next shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, + "Previous shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY, + "Slow motion hold" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY, + "Slow motion toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, + "Savestate slot -" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, + "Savestate slot +" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, + "Volume -" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, + "Volume +" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, + "Display Overlay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, + "Hide Overlay In Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Show Inputs On Overlay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Show Inputs Listen Port" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, + "Poll Type Behavior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, + "Early" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_LATE, + "Late" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_NORMAL, + "Normal" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_PREFER_FRONT_TOUCH, + "Prefer Front Touch" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, + "Input Remapping" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, + "Remap Binds Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, + "Save Autoconfig" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, + "Input" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, + "Small Keyboard Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_ENABLE, + "Touch Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbo enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, + "Turbo Period" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, + "Input User %u Binds" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LATENCY_SETTINGS, + "Latency" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INTERNAL_STORAGE_STATUS, + "Internal storage status" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, + "Input Autoconfig" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, + "Joypad Driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, + "Services" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_CHINESE_SIMPLIFIED, + "Chinese (Simplified)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_CHINESE_TRADITIONAL, + "Chinese (Traditional)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_DUTCH, + "Dutch" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_ENGLISH, + "English" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_ESPERANTO, + "Esperanto" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_FRENCH, + "French" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_GERMAN, + "German" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_ITALIAN, + "Italian" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_JAPANESE, + "Japanese" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_KOREAN, + "Korean" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_POLISH, + "Polish" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_BRAZIL, + "Portuguese (Brazil)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_PORTUGAL, + "Portuguese (Portugal)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_RUSSIAN, + "Russian" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_SPANISH, + "Spanish" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE, + "Vietnamese" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_ARABIC, + "Arabic" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, + "Left Analog" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, + "Core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, + "Core Info" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, + "Core Logging Level" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LINEAR, + "Linear" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, + "Load Archive" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, + "Load Recent" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, + "Load Content" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOAD_STATE, + "Load State" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, + "Allow Location" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER, + "Location Driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, + "Logging" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY, + "Logging Verbosity" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MAIN_MENU, + "Main Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MANAGEMENT, + "Database Settings" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, + "Menu Color Theme" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE, + "Blue" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, + "Blue Grey" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_DARK_BLUE, + "Dark Blue" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GREEN, + "Green" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_NVIDIA_SHIELD, + "Shield" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_RED, + "Red" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_YELLOW, + "Yellow" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, + "Footer Opacity" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, + "Header Opacity" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_DRIVER, + "Menu Driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, + "Throttle Menu Framerate" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, + "Settings" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, + "Menu Linear Filter" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, + "Horizontal Animation" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, + "Appearance" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, + "Background" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, + "Background opacity" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MISSING, + "Missing" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MORE, + "..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MOUSE_ENABLE, + "Mouse Support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MULTIMEDIA_SETTINGS, + "Multimedia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MUSIC_TAB, + "Music" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Filter unknown extensions" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, + "Navigation Wrap-Around" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NEAREST, + "Nearest" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY, + "Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_SLAVES, + "Allow Slave-Mode Clients" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, + "Netplay Check Frames" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Input Latency Frames" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "Input Latency Frames Range" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, + "Netplay Delay Frames" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, + "Disconnect from netplay host" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, + "Netplay Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, + "Connect to netplay host" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, + "Start netplay host" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, + "Stop netplay host" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, + "Server Address" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, + "Scan local network" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, + "Netplay Client Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, + "Username" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, + "Server Password" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, + "Publicly Announce Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_REQUEST_DEVICE_I, + "Request Device %u" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_REQUIRE_SLAVES, + "Disallow Non-Slave-Mode Clients" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, + "Netplay settings" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG, + "Analog Input Sharing" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_MAX, + "Max" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_AVERAGE, + "Average" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL, + "Digital Input Sharing" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_OR, + "Share" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_XOR, + "Grapple" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_VOTE, + "Vote" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NONE, + "None" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NO_PREFERENCE, + "No preference" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_START_AS_SPECTATOR, + "Netplay Spectator Mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, + "Netplay Stateless Mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, + "Server Spectate-Only Password" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, + "Netplay Spectator Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, + "Netplay TCP Port" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, + "Netplay NAT Traversal" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, + "Network Commands" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, + "Network Command Port" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION, + "Network Information" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, + "Network Gamepad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, + "Network Remote Base Port" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, + "Network" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO, + "No" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NONE, + "None" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE, + "N/A" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY, + "No achievements to display." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORE, + "No Core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, + "No cores available." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, + "No core information available." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, + "No core options available." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, + "No entries to display." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, + "No history available." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, + "No information is available." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_ITEMS, + "No items." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, + "No netplay hosts found." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, + "No networks found." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, + "No performance counters." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, + "No playlists." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, + "No playlist entries available." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, + "No settings found." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, + "No shader parameters." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OFF, + "OFF" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ON, + "ON" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONLINE, + "Online" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, + "Online Updater" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, + "Onscreen Display" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, + "Onscreen Overlay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONSCREEN_OVERLAY_SETTINGS, + "Adjust Bezels and Onscreen controls" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, + "Onscreen Notifications" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONSCREEN_NOTIFICATIONS_SETTINGS, + "Adjust the Onscreen Notifications" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, + "Browse Archive" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OPTIONAL, + "Optional" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY, + "Overlay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, + "Autoload Preferred Overlay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, + "Overlay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, + "Overlay Opacity" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, + "Overlay Preset" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, + "Overlay Scale" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, + "Onscreen Overlay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, + "Use PAL60 Mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, + "Parent directory" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, + "Pause when menu activated" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE, + "Don't run in background" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE, + "Performance Counters" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB, + "Playlists" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, + "Playlist" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, + "Playlists" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, + "Touch Support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PORT, + "Port" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PRESENT, + "Present" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS, + "Privacy" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIDI_SETTINGS, + "MIDI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, + "Quit RetroArch" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG, + "Analog supported" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, + "BBFC Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CERO_RATING, + "CERO Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_COOP, + "Co-op supported" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CRC32, + "CRC32" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DESCRIPTION, + "Description" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER, + "Developer" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, + "Edge Magazine Issue" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING, + "Edge Magazine Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_REVIEW, + "Edge Magazine Review" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ELSPA_RATING, + "ELSPA Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, + "Enhancement Hardware" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ESRB_RATING, + "ESRB Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FAMITSU_MAGAZINE_RATING, + "Famitsu Magazine Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE, + "Franchise" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GENRE, + "Genre" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MD5, + "MD5" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME, + "Name" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ORIGIN, + "Origin" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PEGI_RATING, + "PEGI Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, + "Publisher" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, + "Releasedate Month" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, + "Releasedate Year" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RUMBLE, + "Rumble supported" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SERIAL, + "Serial" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1, + "SHA1" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, + "Start Content" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, + "TGDB Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REBOOT, + "Reboot" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, + "Recording Config" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, + "Recording Output" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS, + "Recording" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, + "Load Recording Config..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, + "Record Driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIDI_DRIVER, + "MIDI Driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, + "Enable Recording" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_PATH, + "Save Output Recording as..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, + "Save Recordings in Output Dir" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE, + "Remap File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, + "Load Remap File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, + "Save Core Remap File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CONTENT_DIR, + "Save Content Directory Remap File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, + "Save Game Remap File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE, + "Delete Core Remap File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME, + "Delete Game Remap File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CONTENT_DIR, + "Delete Game Content Directory Remap File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REQUIRED, + "Required" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, + "Restart" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RESTART_RETROARCH, + "Restart RetroArch" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RESUME, + "Resume" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, + "Resume" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, + "RetroKeyboard" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RETROPAD, + "RetroPad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, + "RetroPad w/ Analog" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, + "Achievements" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_ENABLE, + "Rewind Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_AFTER_TOGGLE, + "Apply After Toggle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_AFTER_LOAD, + "Auto-Apply Cheats During Game Load" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_GRANULARITY, + "Rewind Granularity" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE, + "Rewind Buffer Size (MB)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE_STEP, + "Rewind Buffer Size Step (MB)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, + "Rewind" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SETTINGS, + "Cheat Settings" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DETAILS_SETTINGS, + "Cheat Details" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_SETTINGS, + "Start or Continue Cheat Search" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, + "File Browser" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, + "Config" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, + "Display Start Screen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, + "Right Analog" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, + "Add to Favorites" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES_PLAYLIST, + "Add to Favorites" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RESET_CORE_ASSOCIATION, + "Reset Core Association" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN, + "Run" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_MUSIC, + "Run" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, + "SAMBA Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, + "Savefile" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, + "Save State Auto Index" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, + "Auto Load State" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, + "Auto Save State" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, + "Savestate" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, + "Savestate Thumbnails" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, + "Save Current Configuration" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Save Core Overrides" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, + "Save Content Directory Overrides" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, + "Save Game Overrides" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, + "Save New Configuration" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_STATE, + "Save State" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, + "Saving" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, + "Scan Directory" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCAN_FILE, + "Scan File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, + "Screenshot" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, + "Screen Resolution" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SEARCH, + "Search" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SECONDS, + "seconds" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS, + "Settings" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, + "Settings" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER, + "Shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, + "Apply Changes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS, + "Shaders" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON, + "Ribbon" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON_SIMPLIFIED, + "Ribbon (simplified)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SIMPLE_SNOW, + "Simple Snow" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOW, + "Snow" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, + "Show Advanced Settings" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, + "Show Hidden Files and Folders" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHUTDOWN, + "Shutdown" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, + "Slow-Motion Ratio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_ENABLED, + "Run-Ahead to Reduce Latency" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_FRAMES, + "Number of Frames to Run Ahead" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_SECONDARY_INSTANCE, + "RunAhead Use Second Instance" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_HIDE_WARNINGS, + "RunAhead Hide Warnings" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, + "Sort Saves In Folders" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, + "Sort Savestates In Folders" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE, + "Write Savestates to Content Dir" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE, + "Write Saves to Content Dir" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + "System Files are in Content Dir" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + "Write Screenshots to Content Dir" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SSH_ENABLE, + "SSH Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_START_CORE, + "Start Core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD, + "Start Remote RetroPad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, + "Start Video Processor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STATE_SLOT, + "State Slot" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STATUS, + "Status" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE, + "stdin Commands" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SUPPORTED_CORES, + "Suggested cores" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SUSPEND_SCREENSAVER_ENABLE, + "Suspend Screensaver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE, + "System BGM Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, + "System/BIOS" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, + "System Information" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT, + "7zip support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT, + "ALSA support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_BUILD_DATE, + "Build date" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CG_SUPPORT, + "Cg support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COCOA_SUPPORT, + "Cocoa support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COMMAND_IFACE_SUPPORT, + "Command interface support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CORETEXT_SUPPORT, + "CoreText support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CPU_FEATURES, + "CPU Features" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_DPI, + "Display metric DPI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT, + "Display metric height (mm)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH, + "Display metric width (mm)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DSOUND_SUPPORT, + "DirectSound support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT, + "WASAPI support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, + "Dynamic library support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, + "Dynamic run-time loading of libretro library" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT, + "EGL support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT, + "OpenGL/Direct3D render-to-texture (multi-pass shaders) support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FFMPEG_SUPPORT, + "FFmpeg support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FREETYPE_SUPPORT, + "FreeType support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER, + "Frontend identifier" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_NAME, + "Frontend name" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_OS, + "Frontend OS" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GIT_VERSION, + "Git version" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GLSL_SUPPORT, + "GLSL support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_HLSL_SUPPORT, + "HLSL support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_JACK_SUPPORT, + "JACK support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_KMS_SUPPORT, + "KMS/EGL support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LAKKA_VERSION, + "Lakka Version" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBRETRODB_SUPPORT, + "LibretroDB support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, + "Libusb support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBXML2_SUPPORT, + "libxml2 XML parsing support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, + "Netplay (peer-to-peer) support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, + "Network Command interface support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_REMOTE_SUPPORT, + "Network Gamepad support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT, + "OpenAL support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT, + "OpenGL ES support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGL_SUPPORT, + "OpenGL support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENSL_SUPPORT, + "OpenSL support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENVG_SUPPORT, + "OpenVG support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OSS_SUPPORT, + "OSS support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OVERLAY_SUPPORT, + "Overlay support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE, + "Power source" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGED, + "Charged" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGING, + "Charging" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_DISCHARGING, + "Discharging" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE, + "No source" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, + "PulseAudio support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PYTHON_SUPPORT, + "Python (script support in shaders) support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RBMP_SUPPORT, + "BMP support (RBMP)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RETRORATING_LEVEL, + "RetroRating level" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RJPEG_SUPPORT, + "JPEG support (RJPEG)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ROARAUDIO_SUPPORT, + "RoarAudio support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RPNG_SUPPORT, + "PNG support (RPNG)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RSOUND_SUPPORT, + "RSound support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RTGA_SUPPORT, + "TGA support (RTGA)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, + "SDL2 support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_IMAGE_SUPPORT, + "SDL image support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_SUPPORT, + "SDL1.2 support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SLANG_SUPPORT, + "Slang support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_THREADING_SUPPORT, + "Threading support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, + "Udev support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, + "Video4Linux2 support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER, + "Video context driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, + "Vulkan support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_METAL_SUPPORT, + "Metal support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT, + "Wayland support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_X11_SUPPORT, + "X11 support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XAUDIO2_SUPPORT, + "XAudio2 support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT, + "XVideo support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT, + "Zlib support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, + "Take Screenshot" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, + "Threaded tasks" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAILS, + "Thumbnails" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS, + "Left Thumbnails" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_VERTICAL_THUMBNAILS, + "Thumbnails Vertical Disposition" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, + "Thumbnails" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, + "Thumbnails Updater" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, + "Boxarts" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, + "Screenshots" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, + "Title Screens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, + "Show date / time" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TITLE_COLOR, + "Menu title color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TRUE, + "True" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, + "UI Companion Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, + "UI Companion Start On Boot" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UI_COMPANION_TOGGLE, + "Show desktop menu on startup" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DESKTOP_MENU_ENABLE, + "Enable desktop menu (restart)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, + "Menubar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE, + "Unable to read compressed file." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, + "Undo Load State" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, + "Undo Save State" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UNKNOWN, + "Unknown" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, + "Updater" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, + "Update Assets" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, + "Update Joypad Profiles" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, + "Update Cg Shaders" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, + "Update Cheats" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, + "Update Core Info Files" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, + "Update Databases" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, + "Update GLSL Shaders" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, + "Update Lakka" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, + "Update Overlays" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_SLANG_SHADERS, + "Update Slang Shaders" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USER, + "User" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_KEYBOARD, + "Kbd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS, + "User Interface" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USER_LANGUAGE, + "Language" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USER_SETTINGS, + "User" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Use Builtin Image Viewer" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Use Builtin Media Player" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, + "Allow rotation" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO, + "Config Aspect Ratio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, + "Auto Aspect Ratio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, + "Aspect Ratio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, + "Black Frame Insertion" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, + "Crop Overscan (Reload)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, + "Disable Desktop Composition" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER, + "Video Driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER, + "Video Filter" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, + "Video Filter" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, + "Flicker filter" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, + "Enable Onscreen Notifications" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, + "Notification Font" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, + "Notification Size" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, + "Force aspect ratio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE, + "Force-disable sRGB FBO" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, + "Frame Delay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, + "Start in Fullscreen Mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, + "Video Gamma" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, + "Use GPU Recording" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, + "GPU Screenshot Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC, + "Hard GPU Sync" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC_FRAMES, + "Hard GPU Sync Frames" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Max swapchain images" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, + "Notification X Position" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, + "Notification Y Position" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, + "Monitor Index" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, + "Use Post Filter Recording" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, + "Vertical Refresh Rate" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, + "Estimated Screen Framerate" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_POLLED, + "Set Display-Reported Refresh Rate" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ROTATION, + "Rotation" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE, + "Windowed Scale" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, + "Integer Scale" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, + "Video" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, + "Video Shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, + "Shader Passes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, + "Shader Parameters" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, + "Load Shader Preset" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, + "Save Shader Preset As" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, + "Save Core Preset" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT, + "Save Content Directory Preset" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, + "Save Game Preset" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, + "Enable Hardware Shared Context" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, + "Bilinear Filtering" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, + "Soft Filter Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, + "Vertical Sync (Vsync) Swap Interval" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_TAB, + "Video" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, + "Threaded Video" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, + "Deflicker" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, + "Custom Aspect Ratio Height" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, + "Custom Aspect Ratio Width" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, + "Custom Aspect Ratio X Pos." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, + "Custom Aspect Ratio Y Pos." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, + "Set VI Screen Width" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, + "Vertical Sync (Vsync)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, + "Windowed Fullscreen Mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, + "Window Width" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, + "Window Height" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_X, + "Fullscreen Width" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_Y, + "Fullscreen Height" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, + "Wi-Fi Driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, + "Wi-Fi" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, + "Menu Alpha Factor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_RED, + "Menu Font Red Color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_GREEN, + "Menu Font Green Color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_BLUE, + "Menu Font Blue Color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_FONT, + "Menu Font" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, + "Custom" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, + "FlatUI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME, + "Monochrome" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME_INVERTED, + "Monochrome Inverted" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_SYSTEMATIC, + "Systematic" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_NEOACTIVE, + "NeoActive" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_PIXEL, + "Pixel" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, + "RetroActive" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROSYSTEM, + "Retrosystem" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, + "Dot-Art" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, + "Menu Color Theme" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_APPLE_GREEN, + "Apple Green" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK, + "Dark" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LIGHT, + "Light" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MORNING_BLUE, + "Morning Blue" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK_PURPLE, + "Dark Purple" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ELECTRIC_BLUE, + "Electric Blue" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GOLDEN, + "Golden" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LEGACY_RED, + "Legacy Red" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDNIGHT_BLUE, + "Midnight Blue" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_PLAIN, + "Plain" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, + "Undersea" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, + "Volcanic Red" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, + "Menu Shader Pipeline" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, + "Menu Scale Factor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, + "Icon Shadows Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_HISTORY, + "Show History Tab" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, + "Show Import content Tab" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, + "Show Playlist Tabs" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_FAVORITES, + "Show Favorites Tab" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_IMAGES, + "Show Image Tab" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_MUSIC, + "Show Music Tab" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS, + "Show Settings Tab" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO, + "Show Video Tab" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, + "Show Netplay Tab" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_LAYOUT, + "Menu Layout" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_THEME, + "Menu Icon Theme" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_YES, + "Yes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, + "Shader Preset" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, + "Enable or disable achievements. For more information, visit http://retroachievements.org" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, + "Enable or disable unofficial achievements and/or beta features for testing purposes." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, + "Enable or disable savestates, cheats, rewind, pause, and slow-motion for all games." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_LEADERBOARDS_ENABLE, + "Enable or disable in-game leaderboards. Has no effect if Hardcore Mode is disabled." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_BADGES_ENABLE, + "Enable or disable badge display in the Achievement List." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE, + "Enable or disable OSD verbosity for achievements." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_AUTO_SCREENSHOT, + "Automatically take a screenshot when an achievement is triggered." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, + "Change drivers used by the system." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, + "Change achievement settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_SETTINGS, + "Change core settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, + "Change recording settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, + "Change display overlay and keyboard overlay, and onscreen notification settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, + "Change rewind, fast-forward, and slow-motion settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVING_SETTINGS, + "Change saving settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, + "Change logging settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, + "Change user interface settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_USER_SETTINGS, + "Change account, username, and language settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, + "Change your privacy settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIDI_SETTINGS, + "Change MIDI settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, + "Change default directories where files are located." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, + "Change playlist settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, + "Configure server and network settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, + "Scan content and add to the database." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, + "Change audio output settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, + "Enable or disable bluetooth." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, + "Saves changes to the configuration file on exit." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, + "Change default settings for configuration files." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, + "Manage and create configuration files." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CPU_CORES, + "Amount of cores that the CPU has." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FPS_SHOW, + "Displays the current framerate per second onscreen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, + "Configure hotkey settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, + "Gamepad button combination to toggle menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_SETTINGS, + "Change joypad, keyboard, and mouse settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, + "Configure controls for this user." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LATENCY_SETTINGS, + "Change settings related to video, audio and input latency." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOG_VERBOSITY, + "Enable or disable logging to the terminal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY, + "Join or host a netplay session." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, + "Search for and connect to netplay hosts on the local network." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, + "Display system information." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONLINE_UPDATER, + "Download add-ons, components, and content for RetroArch." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAMBA_ENABLE, + "Enable or disable network sharing of your folders." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, + "Manage operating system level services." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, + "Show hidden files/directories inside the file browser." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SSH_ENABLE, + "Enable or disable remote command line access." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, + "Prevents your system's screensaver from becoming active." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, + "Sets the window size relative to the core viewport size. Alternatively, you can set a window width and height below for a fixed window size." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_USER_LANGUAGE, + "Sets the language of the interface." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, + "Inserts a black frame inbetween frames. Useful for users with 120Hz screens who want to play 60Hz content to eliminate ghosting." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, + "Reduces latency at the cost of a higher risk of video stuttering. Adds a delay after V-Sync (in ms)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, + "Sets how many frames the CPU can run ahead of the GPU when using 'Hard GPU Sync'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Tells the video driver to explicitly use a specified buffering mode." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, + "Selects which display screen to use." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, + "The accurate estimated refresh rate of the screen in Hz." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_POLLED, + "The refresh rate as reported by the display driver." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, + "Change video output settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_WIFI_SETTINGS, + "Scans for wireless networks and establishes connection." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_HELP_LIST, + "Learn more about how the program works." + ) +MSG_HASH( + MSG_ADDED_TO_FAVORITES, + "Added to favorites" + ) +MSG_HASH( + MSG_RESET_CORE_ASSOCIATION, + "Playlist entry core association has been reset." + ) +MSG_HASH( + MSG_APPENDED_DISK, + "Appended disk" + ) +MSG_HASH( + MSG_APPLICATION_DIR, + "Application Dir" + ) +MSG_HASH( + MSG_APPLYING_CHEAT, + "Applying cheat changes." + ) +MSG_HASH( + MSG_APPLYING_SHADER, + "Applying shader" + ) +MSG_HASH( + MSG_AUDIO_MUTED, + "Audio muted." + ) +MSG_HASH( + MSG_AUDIO_UNMUTED, + "Audio unmuted." + ) +MSG_HASH( + MSG_AUTOCONFIG_FILE_ERROR_SAVING, + "Error saving autoconf file." + ) +MSG_HASH( + MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, + "Autoconfig file saved successfully." + ) +MSG_HASH( + MSG_AUTOSAVE_FAILED, + "Could not initialize autosave." + ) +MSG_HASH( + MSG_AUTO_SAVE_STATE_TO, + "Auto save state to" + ) +MSG_HASH( + MSG_BLOCKING_SRAM_OVERWRITE, + "Blocking SRAM Overwrite" + ) +MSG_HASH( + MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, + "Bringing up command interface on port" + ) +MSG_HASH( + MSG_BYTES, + "bytes" + ) +MSG_HASH( + MSG_CANNOT_INFER_NEW_CONFIG_PATH, + "Cannot infer new config path. Use current time." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_ENABLE, + "Hardcore Mode Enabled, savestate & rewind were disabled." + ) +MSG_HASH( + MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, + "Comparing with known magic numbers..." + ) +MSG_HASH( + MSG_COMPILED_AGAINST_API, + "Compiled against API" + ) +MSG_HASH( + MSG_CONFIG_DIRECTORY_NOT_SET, + "Config directory not set. Cannot save new config." + ) +MSG_HASH( + MSG_CONNECTED_TO, + "Connected to" + ) +MSG_HASH( + MSG_CONTENT_CRC32S_DIFFER, + "Content CRC32s differ. Cannot use different games." + ) +MSG_HASH( + MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, + "Content loading skipped. Implementation will load it on its own." + ) +MSG_HASH( + MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, + "Core does not support save states." + ) +MSG_HASH( + MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, + "Core options file created successfully." + ) +MSG_HASH( + MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, + "Could not find any next driver" + ) +MSG_HASH( + MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, + "Could not find compatible system." + ) +MSG_HASH( + MSG_COULD_NOT_FIND_VALID_DATA_TRACK, + "Could not find valid data track" + ) +MSG_HASH( + MSG_COULD_NOT_OPEN_DATA_TRACK, + "could not open data track" + ) +MSG_HASH( + MSG_COULD_NOT_READ_CONTENT_FILE, + "Could not read content file" + ) +MSG_HASH( + MSG_COULD_NOT_READ_MOVIE_HEADER, + "Could not read movie header." + ) +MSG_HASH( + MSG_COULD_NOT_READ_STATE_FROM_MOVIE, + "Could not read state from movie." + ) +MSG_HASH( + MSG_CRC32_CHECKSUM_MISMATCH, + "CRC32 checksum mismatch between content file and saved content checksum in replay file header. Replay highly likely to desync on playback." + ) +MSG_HASH( + MSG_CUSTOM_TIMING_GIVEN, + "Custom timing given" + ) +MSG_HASH( + MSG_DECOMPRESSION_ALREADY_IN_PROGRESS, + "Decompression already in progress." + ) +MSG_HASH( + MSG_DECOMPRESSION_FAILED, + "Decompression failed." + ) +MSG_HASH( + MSG_DETECTED_VIEWPORT_OF, + "Detected viewport of" + ) +MSG_HASH( + MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, + "Did not find a valid content patch." + ) +MSG_HASH( + MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, + "Disconnect device from a valid port." + ) +MSG_HASH( + MSG_DISK_CLOSED, + "Closed" + ) +MSG_HASH( + MSG_DISK_EJECTED, + "Ejected" + ) +MSG_HASH( + MSG_DOWNLOADING, + "Downloading" + ) +MSG_HASH( + MSG_INDEX_FILE, + "index" + ) +MSG_HASH( + MSG_DOWNLOAD_FAILED, + "Download failed" + ) +MSG_HASH( + MSG_ERROR, + "Error" + ) +MSG_HASH( + MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, + "Libretro core requires content, but nothing was provided." + ) +MSG_HASH( + MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT, + "Libretro core requires special content, but none were provided." + ) +MSG_HASH( + MSG_ERROR_PARSING_ARGUMENTS, + "Error parsing arguments." + ) +MSG_HASH( + MSG_ERROR_SAVING_CORE_OPTIONS_FILE, + "Error saving core options file." + ) +MSG_HASH( + MSG_ERROR_SAVING_REMAP_FILE, + "Error saving remap file." + ) +MSG_HASH( + MSG_ERROR_REMOVING_REMAP_FILE, + "Error removing remap file." + ) +MSG_HASH( + MSG_ERROR_SAVING_SHADER_PRESET, + "Error saving shader preset." + ) +MSG_HASH( + MSG_EXTERNAL_APPLICATION_DIR, + "External Application Dir" + ) +MSG_HASH( + MSG_EXTRACTING, + "Extracting" + ) +MSG_HASH( + MSG_EXTRACTING_FILE, + "Extracting file" + ) +MSG_HASH( + MSG_FAILED_SAVING_CONFIG_TO, + "Failed saving config to" + ) +MSG_HASH( + MSG_FAILED_TO, + "Failed to" + ) +MSG_HASH( + MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, + "Failed to accept incoming spectator." + ) +MSG_HASH( + MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, + "Failed to allocate memory for patched content..." + ) +MSG_HASH( + MSG_FAILED_TO_APPLY_SHADER, + "Failed to apply shader." + ) +MSG_HASH( + MSG_FAILED_TO_BIND_SOCKET, + "Failed to bind socket." + ) +MSG_HASH( + MSG_FAILED_TO_CREATE_THE_DIRECTORY, + "Failed to create the directory." + ) +MSG_HASH( + MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, + "Failed to extract content from compressed file" + ) +MSG_HASH( + MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, + "Failed to get nickname from client." + ) +MSG_HASH( + MSG_FAILED_TO_LOAD, + "Failed to load" + ) +MSG_HASH( + MSG_FAILED_TO_LOAD_CONTENT, + "Failed to load content" + ) +MSG_HASH( + MSG_FAILED_TO_LOAD_MOVIE_FILE, + "Failed to load movie file" + ) +MSG_HASH( + MSG_FAILED_TO_LOAD_OVERLAY, + "Failed to load overlay." + ) +MSG_HASH( + MSG_FAILED_TO_LOAD_STATE, + "Failed to load state from" + ) +MSG_HASH( + MSG_FAILED_TO_OPEN_LIBRETRO_CORE, + "Failed to open libretro core" + ) +MSG_HASH( + MSG_FAILED_TO_PATCH, + "Failed to patch" + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT, + "Failed to receive header from client." + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_NICKNAME, + "Failed to receive nickname." + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST, + "Failed to receive nickname from host." + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_NICKNAME_SIZE_FROM_HOST, + "Failed to receive nickname size from host." + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST, + "Failed to receive SRAM data from host." + ) +MSG_HASH( + MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY, + "Failed to remove disk from tray." + ) +MSG_HASH( + MSG_FAILED_TO_REMOVE_TEMPORARY_FILE, + "Failed to remove temporary file" + ) +MSG_HASH( + MSG_FAILED_TO_SAVE_SRAM, + "Failed to save SRAM" + ) +MSG_HASH( + MSG_FAILED_TO_SAVE_STATE_TO, + "Failed to save state to" + ) +MSG_HASH( + MSG_FAILED_TO_SEND_NICKNAME, + "Failed to send nickname." + ) +MSG_HASH( + MSG_FAILED_TO_SEND_NICKNAME_SIZE, + "Failed to send nickname size." + ) +MSG_HASH( + MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT, + "Failed to send nickname to client." + ) +MSG_HASH( + MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, + "Failed to send nickname to host." + ) +MSG_HASH( + MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, + "Failed to send SRAM data to client." + ) +MSG_HASH( + MSG_FAILED_TO_START_AUDIO_DRIVER, + "Failed to start audio driver. Will continue without audio." + ) +MSG_HASH( + MSG_FAILED_TO_START_MOVIE_RECORD, + "Failed to start movie record." + ) +MSG_HASH( + MSG_FAILED_TO_START_RECORDING, + "Failed to start recording." + ) +MSG_HASH( + MSG_FAILED_TO_TAKE_SCREENSHOT, + "Failed to take screenshot." + ) +MSG_HASH( + MSG_FAILED_TO_UNDO_LOAD_STATE, + "Failed to undo load state." + ) +MSG_HASH( + MSG_FAILED_TO_UNDO_SAVE_STATE, + "Failed to undo save state." + ) +MSG_HASH( + MSG_FAILED_TO_UNMUTE_AUDIO, + "Failed to unmute audio." + ) +MSG_HASH( + MSG_FATAL_ERROR_RECEIVED_IN, + "Fatal error received in" + ) +MSG_HASH( + MSG_FILE_NOT_FOUND, + "File not found" + ) +MSG_HASH( + MSG_FOUND_AUTO_SAVESTATE_IN, + "Found auto savestate in" + ) +MSG_HASH( + MSG_FOUND_DISK_LABEL, + "Found disk label" + ) +MSG_HASH( + MSG_FOUND_FIRST_DATA_TRACK_ON_FILE, + "Found first data track on file" + ) +MSG_HASH( + MSG_FOUND_LAST_STATE_SLOT, + "Found last state slot" + ) +MSG_HASH( + MSG_FOUND_SHADER, + "Found shader" + ) +MSG_HASH( + MSG_FRAMES, + "Frames" + ) +MSG_HASH( + MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT, + "Per-Game Options: game-specific core options found at" + ) +MSG_HASH( + MSG_GOT_INVALID_DISK_INDEX, + "Got invalid disk index." + ) +MSG_HASH( + MSG_GRAB_MOUSE_STATE, + "Grab mouse state" + ) +MSG_HASH( + MSG_GAME_FOCUS_ON, + "Game focus on" + ) +MSG_HASH( + MSG_GAME_FOCUS_OFF, + "Game focus off" + ) +MSG_HASH( + MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, + "Libretro core is hardware rendered. Must use post-shaded recording as well." + ) +MSG_HASH( + MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, + "Inflated checksum did not match CRC32." + ) +MSG_HASH( + MSG_INPUT_CHEAT, + "Input Cheat" + ) +MSG_HASH( + MSG_INPUT_CHEAT_FILENAME, + "Input Cheat Filename" + ) +MSG_HASH( + MSG_INPUT_PRESET_FILENAME, + "Input Preset Filename" + ) +MSG_HASH( + MSG_INPUT_RENAME_ENTRY, + "Rename Title" + ) +MSG_HASH( + MSG_INTERFACE, + "Interface" + ) +MSG_HASH( + MSG_INTERNAL_STORAGE, + "Internal Storage" + ) +MSG_HASH( + MSG_REMOVABLE_STORAGE, + "Removable Storage" + ) +MSG_HASH( + MSG_INVALID_NICKNAME_SIZE, + "Invalid nickname size." + ) +MSG_HASH( + MSG_IN_BYTES, + "in bytes" + ) +MSG_HASH( + MSG_IN_GIGABYTES, + "in gigabytes" + ) +MSG_HASH( + MSG_IN_MEGABYTES, + "in megabytes" + ) +MSG_HASH( + MSG_LIBRETRO_ABI_BREAK, + "is compiled against a different version of libretro than this libretro implementation." + ) +MSG_HASH( + MSG_LIBRETRO_FRONTEND, + "Frontend for libretro" + ) +MSG_HASH( + MSG_LOADED_STATE_FROM_SLOT, + "Loaded state from slot #%d." + ) +MSG_HASH( + MSG_LOADED_STATE_FROM_SLOT_AUTO, + "Loaded state from slot #-1 (auto)." + ) +MSG_HASH( + MSG_LOADING, + "Loading" + ) +MSG_HASH( + MSG_FIRMWARE, + "One or more firmware files are missing" + ) +MSG_HASH( + MSG_LOADING_CONTENT_FILE, + "Loading content file" + ) +MSG_HASH( + MSG_LOADING_HISTORY_FILE, + "Loading history file" + ) +MSG_HASH( + MSG_LOADING_STATE, + "Loading state" + ) +MSG_HASH( + MSG_MEMORY, + "Memory" + ) +MSG_HASH( + MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, + "Movie file is not a valid BSV1 file." + ) +MSG_HASH( + MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, + "Movie format seems to have a different serializer version. Will most likely fail." + ) +MSG_HASH( + MSG_MOVIE_PLAYBACK_ENDED, + "Movie playback ended." + ) +MSG_HASH( + MSG_MOVIE_RECORD_STOPPED, + "Stopping movie record." + ) +MSG_HASH( + MSG_NETPLAY_FAILED, + "Failed to initialize netplay." + ) +MSG_HASH( + MSG_NO_CONTENT_STARTING_DUMMY_CORE, + "No content, starting dummy core." + ) +MSG_HASH( + MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, + "No save state has been overwritten yet." + ) +MSG_HASH( + MSG_NO_STATE_HAS_BEEN_LOADED_YET, + "No state has been loaded yet." + ) +MSG_HASH( + MSG_OVERRIDES_ERROR_SAVING, + "Error saving overrides." + ) +MSG_HASH( + MSG_OVERRIDES_SAVED_SUCCESSFULLY, + "Overrides saved successfully." + ) +MSG_HASH( + MSG_PAUSED, + "Paused." + ) +MSG_HASH( + MSG_PROGRAM, + "RetroArch" + ) +MSG_HASH( + MSG_READING_FIRST_DATA_TRACK, + "Reading first data track..." + ) +MSG_HASH( + MSG_RECEIVED, + "received" + ) +MSG_HASH( + MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, + "Recording terminated due to resize." + ) +MSG_HASH( + MSG_RECORDING_TO, + "Recording to" + ) +MSG_HASH( + MSG_REDIRECTING_CHEATFILE_TO, + "Redirecting cheat file to" + ) +MSG_HASH( + MSG_REDIRECTING_SAVEFILE_TO, + "Redirecting save file to" + ) +MSG_HASH( + MSG_REDIRECTING_SAVESTATE_TO, + "Redirecting savestate to" + ) +MSG_HASH( + MSG_REMAP_FILE_SAVED_SUCCESSFULLY, + "Remap file saved successfully." + ) +MSG_HASH( + MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, + "Remap file removed successfully." + ) +MSG_HASH( + MSG_REMOVED_DISK_FROM_TRAY, + "Removed disk from tray." + ) +MSG_HASH( + MSG_REMOVING_TEMPORARY_CONTENT_FILE, + "Removing temporary content file" + ) +MSG_HASH( + MSG_RESET, + "Reset" + ) +MSG_HASH( + MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT, + "Restarting recording due to driver reinit." + ) +MSG_HASH( + MSG_RESTORED_OLD_SAVE_STATE, + "Restored old save state." + ) +MSG_HASH( + MSG_RESTORING_DEFAULT_SHADER_PRESET_TO, + "Shaders: restoring default shader preset to" + ) +MSG_HASH( + MSG_REVERTING_SAVEFILE_DIRECTORY_TO, + "Reverting savefile directory to" + ) +MSG_HASH( + MSG_REVERTING_SAVESTATE_DIRECTORY_TO, + "Reverting savestate directory to" + ) +MSG_HASH( + MSG_REWINDING, + "Rewinding." + ) +MSG_HASH( + MSG_REWIND_INIT, + "Initializing rewind buffer with size" + ) +MSG_HASH( + MSG_REWIND_INIT_FAILED, + "Failed to initialize rewind buffer. Rewinding will be disabled." + ) +MSG_HASH( + MSG_REWIND_INIT_FAILED_THREADED_AUDIO, + "Implementation uses threaded audio. Cannot use rewind." + ) +MSG_HASH( + MSG_REWIND_REACHED_END, + "Reached end of rewind buffer." + ) +MSG_HASH( + MSG_SAVED_NEW_CONFIG_TO, + "Saved new config to" + ) +MSG_HASH( + MSG_SAVED_STATE_TO_SLOT, + "Saved state to slot #%d." + ) +MSG_HASH( + MSG_SAVED_STATE_TO_SLOT_AUTO, + "Saved state to slot #-1 (auto)." + ) +MSG_HASH( + MSG_SAVED_SUCCESSFULLY_TO, + "Saved successfully to" + ) +MSG_HASH( + MSG_SAVING_RAM_TYPE, + "Saving RAM type" + ) +MSG_HASH( + MSG_SAVING_STATE, + "Saving state" + ) +MSG_HASH( + MSG_SCANNING, + "Scanning" + ) +MSG_HASH( + MSG_SCANNING_OF_DIRECTORY_FINISHED, + "Scanning of directory finished" + ) +MSG_HASH( + MSG_SENDING_COMMAND, + "Sending command" + ) +MSG_HASH( + MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED, + "Several patches are explicitly defined, ignoring all..." + ) +MSG_HASH( + MSG_SHADER, + "Shader" + ) +MSG_HASH( + MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, + "Shader preset saved successfully." + ) +MSG_HASH( + MSG_SKIPPING_SRAM_LOAD, + "Skipping SRAM load." + ) +MSG_HASH( + MSG_SLOW_MOTION, + "Slow motion." + ) +MSG_HASH( + MSG_FAST_FORWARD, + "Fast forward." + ) +MSG_HASH( + MSG_SLOW_MOTION_REWIND, + "Slow motion rewind." + ) +MSG_HASH( + MSG_SRAM_WILL_NOT_BE_SAVED, + "SRAM will not be saved." + ) +MSG_HASH( + MSG_STARTING_MOVIE_PLAYBACK, + "Starting movie playback." + ) +MSG_HASH( + MSG_STARTING_MOVIE_RECORD_TO, + "Starting movie record to" + ) +MSG_HASH( + MSG_STATE_SIZE, + "State size" + ) +MSG_HASH( + MSG_STATE_SLOT, + "State slot" + ) +MSG_HASH( + MSG_TAKING_SCREENSHOT, + "Taking screenshot." + ) +MSG_HASH( + MSG_TO, + "to" + ) +MSG_HASH( + MSG_UNDID_LOAD_STATE, + "Undid load state." + ) +MSG_HASH( + MSG_UNDOING_SAVE_STATE, + "Undoing save state" + ) +MSG_HASH( + MSG_UNKNOWN, + "Unknown" + ) +MSG_HASH( + MSG_UNPAUSED, + "Unpaused." + ) +MSG_HASH( + MSG_UNRECOGNIZED_COMMAND, + "Unrecognized command" + ) +MSG_HASH( + MSG_USING_CORE_NAME_FOR_NEW_CONFIG, + "Using core name for new config." + ) +MSG_HASH( + MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, + "Using libretro dummy core. Skipping recording." + ) +MSG_HASH( + MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, + "Connect device from a valid port." + ) +MSG_HASH( + MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, + "Disconnecting device from port" + ) +MSG_HASH( + MSG_VALUE_REBOOTING, + "Rebooting..." + ) +MSG_HASH( + MSG_VALUE_SHUTTING_DOWN, + "Shutting down..." + ) +MSG_HASH( + MSG_VERSION_OF_LIBRETRO_API, + "Version of libretro API" + ) +MSG_HASH( + MSG_VIEWPORT_SIZE_CALCULATION_FAILED, + "Viewport size calculation failed! Will continue using raw data. This will probably not work right ..." + ) +MSG_HASH( + MSG_VIRTUAL_DISK_TRAY, + "virtual disk tray." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_LATENCY, + "Desired audio latency in milliseconds. Might not be honored if the audio driver can't provide given latency." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MUTE, + "Mute/unmute audio." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, + "Helps smooth out imperfections in timing when synchronizing audio and video. Be aware that if disabled, proper synchronization is nearly impossible to obtain." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CAMERA_ALLOW, + "Allow or disallow camera access by cores." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOCATION_ALLOW, + "Allow or disallow location services access by cores." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, + "Maximum amount of users supported by RetroArch." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, + "Influence how input polling is done inside RetroArch. Setting it to 'Early' or 'Late' can result in less latency, depending on your configuration." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, + "Allows any user to control the menu. If disabled, only User 1 can control the menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_VOLUME, + "Audio volume (in dB). 0 dB is normal volume, and no gain is applied." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_EXCLUSIVE_MODE, + "Allow the WASAPI driver to take exclusive control of the audio device. If disabled, it will use shared mode instead." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_FLOAT_FORMAT, + "Use float format for the WASAPI driver, if supported by your audio device." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH, + "The intermediate buffer length (in frames) when using the WASAPI driver in shared mode." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_SYNC, + "Synchronize audio. Recommended." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, + "How far an axis must be tilted to result in a button press." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, + "Amount of seconds to wait until proceeding to the next bind." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_BIND_HOLD, + "Amount of seconds to hold an input to bind it." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, + "Describes the period when turbo-enabled buttons are toggled. Numbers are described in frames." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, + "Describes how long the period of a turbo-enabled button should be. Numbers are described in frames." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VSYNC, + "Synchronizes the output video of the graphics card to the refresh rate of the screen. Recommended." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, + "Allow cores to set rotation. When disabled, rotation requests are ignored. Useful for setups where one manually rotates the screen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN, + "Some cores might have a shutdown feature. If enabled, it will prevent the core from shutting RetroArch down. Instead, it loads a dummy core." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, + "Check if all the required firmware is present before attempting to load content." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, + "Vertical refresh rate of your screen. Used to calculate a suitable audio input rate. NOTE: This will be ignored if 'Threaded Video' is enabled." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_ENABLE, + "Enable audio output." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, + "The maximum change in audio input rate. Increasing this enables very large changes in timing at the cost of an inaccurate audio pitch (e.g., running PAL cores on NTSC displays)." + ) +MSG_HASH( + MSG_FAILED, + "failed" + ) +MSG_HASH( + MSG_SUCCEEDED, + "succeeded" + ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED, + "not configured" + ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "not configured, using fallback" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, + "Database Cursor List" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DEVELOPER, + "Database - Filter : Developer" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PUBLISHER, + "Database - Filter : Publisher" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISABLED, + "Disabled" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ENABLED, + "Enabled" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_PATH, + "Content History Path" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ORIGIN, + "Database - Filter : Origin" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_FRANCHISE, + "Database - Filter : Franchise" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ESRB_RATING, + "Database - Filter : ESRB Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ELSPA_RATING, + "Database - Filter : ELSPA Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PEGI_RATING, + "Database - Filter : PEGI Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_CERO_RATING, + "Database - Filter : CERO Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_BBFC_RATING, + "Database - Filter : BBFC Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_MAX_USERS, + "Database - Filter : Max Users" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_MONTH, + "Database - Filter : Releasedate By Month" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_YEAR, + "Database - Filter : Releasedate By Year" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, + "Database - Filter : Edge Magazine Issue" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, + "Database - Filter : Edge Magazine Rating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, + "Database Info" + ) +MSG_HASH( + MSG_WIFI_SCAN_COMPLETE, + "Wi-Fi scan complete." + ) +MSG_HASH( + MSG_SCANNING_WIRELESS_NETWORKS, + "Scanning wireless networks..." + ) +MSG_HASH( + MSG_NETPLAY_LAN_SCAN_COMPLETE, + "Netplay scan complete." + ) +MSG_HASH( + MSG_NETPLAY_LAN_SCANNING, + "Scanning for netplay hosts..." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, + "Pause gameplay when RetroArch is not the active window." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, + "Enable or disable composition." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, + "Enable or disable recent playlist for games, images, music, and videos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, + "Limit the number of entries in recent playlist for games, images, music, and videos." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, + "Unified Menu Controls" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, + "Use the same controls for both the menu and the game. Applies to the keyboard." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, + "Show onscreen messages." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, + "User %d Remote Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, + "Show battery level" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SELECT_FILE, + "Select File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SELECT_FROM_COLLECTION, + "Select From Collection" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FILTER, + "Filter" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCALE, + "Scale" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, + "Netplay will start when content is loaded." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, + "Couldn't find a suitable core or content file, load manually." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, + "Browse URL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BROWSE_URL, + "URL Path" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BROWSE_START, + "Start" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, + "Bokeh" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOWFLAKE, + "Snowflake" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, + "Refresh Room List" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, + "Nickname: %s" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, + "Nickname (lan): %s" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, + "Compatible content found" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, + "Cuts off a few pixels around the edges of the image customarily left blank by developers which sometimes also contain garbage pixels." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, + "Adds a slight blur to the image to take the edge off of the hard pixel edges. This option has very little impact on performance." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FILTER, + "Apply a CPU-powered video filter. NOTE: Might come at a high performance cost. Some video filters might only work for cores that use 32bit or 16bit color." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, + "Input the username of your RetroAchievements account." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, + "Input the password of your RetroAchievements account." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, + "Input your user name here. This will be used for netplay sessions, among other things." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, + "Capture the image after filters (but not shaders) are applied. Your video will look as fancy as what you see on your screen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST, + "Select which core to use." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, + "Select which content to start." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, + "Show network interface(s) and associated IP addresses." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, + "Show information specific to the device." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUIT_RETROARCH, + "Quit the program." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, + "Set the custom width size for the display window. Leaving it at 0 will attempt to scale the window as large as possible." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, + "Set the custom height size for the display window. Leaving it at 0 will attempt to scale the window as large as possible." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, + "Set the custom width size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, + "Set the custom height size for the non-windowed fullscreen mode. Leaving it at 0 will use the desktop resolution" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, + "Specify custom X axis position for onscreen text." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, + "Specify custom Y axis position for onscreen text." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, + "Specify the font size in points." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, + "Hide the overlay while inside the menu, and show it again when exiting the menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Show keyboard/controller inputs on the onscreen overlay." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Select the port for the overlay to listen to if Show Inputs On Overlay is enabled." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, + "Scanned content will appear here." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, + "Only scales video in integer steps. The base size depends on system-reported geometry and aspect ratio. If 'Force Aspect' is not set, X/Y will be integer scaled independently." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_GPU_SCREENSHOT, + "Screenshots output of GPU shaded material if available." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_ROTATION, + "Forces a certain rotation of the screen. The rotation is added to rotations which the core sets." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FORCE_SRGB_DISABLE, + "Forcibly disable sRGB FBO support. Some Intel OpenGL drivers on Windows have video problems with sRGB FBO support if this is enabled. Enabling this can work around it." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN, + "Start in fullscreen. Can be changed at runtime. Can be overridden by a command line switch" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOWED_FULLSCREEN, + "If fullscreen, prefer using a windowed fullscreen mode." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_GPU_RECORD, + "Records output of GPU shaded material if available." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, + "When making a savestate, save state index is automatically increased before it is saved. When loading content, the index will be set to the highest existing index." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, + "Block Save RAM from being overwritten when loading save states. Might potentially lead to buggy games." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FASTFORWARD_RATIO, + "The maximum rate at which content will be run when using fast forward (e.g., 5.0x for 60 fps content = 300 fps cap). If set to 0.0x, fastforward ratio is unlimited (no FPS cap)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, + "When in slow motion, content will slow down by the factor specified/set." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN_AHEAD_ENABLED, + "Run core logic one or more frames ahead then load the state back to reduce perceived input lag." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN_AHEAD_FRAMES, + "The number of frames to run ahead. Causes gameplay issues such as jitter if you exceed the number of lag frames internal to the game." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN_AHEAD_SECONDARY_INSTANCE, + "Use a second instance of the RetroArch core to run ahead. Prevents audio problems due to loading state." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS, + "Hides the warning message that appears when using RunAhead and the core does not support savestates." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_ENABLE, + "Enable rewinding. This will take a performance hit when playing." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_TOGGLE, + "Apply cheat immediately after toggling." ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_LOAD, - "Auto-apply cheats when game loads." + MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_LOAD, + "Auto-apply cheats when game loads." ) MSG_HASH( - MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, - "When rewinding a defined number of frames, you can rewind several frames at a time, increasing the rewind speed." - ) + MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, + "When rewinding a defined number of frames, you can rewind several frames at a time, increasing the rewind speed." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE, - "The amount of memory (in MB) to reserve for the rewind buffer. Increasing this will increase the amount of rewind history." - ) + MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE, + "The amount of memory (in MB) to reserve for the rewind buffer. Increasing this will increase the amount of rewind history." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE_STEP, - "Each time you increase or decrease the rewind buffer size value via this UI it will change by this amount" - ) + MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE_STEP, + "Each time you increase or decrease the rewind buffer size value via this UI it will change by this amount" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_IDX, - "Index position in list." - ) + MENU_ENUM_SUBLABEL_CHEAT_IDX, + "Index position in list." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_ADDRESS_BIT_POSITION, - "Address bitmask when Memory Search Size < 8-bit." -) + MENU_ENUM_SUBLABEL_CHEAT_ADDRESS_BIT_POSITION, + "Address bitmask when Memory Search Size < 8-bit." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_MATCH_IDX, - "Select the match to view." - ) + MENU_ENUM_SUBLABEL_CHEAT_MATCH_IDX, + "Select the match to view." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_START_OR_CONT, - "" - ) + MENU_ENUM_SUBLABEL_CHEAT_START_OR_CONT, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_START_OR_RESTART, - "Left/Right to change bit-size" - ) + MENU_ENUM_SUBLABEL_CHEAT_START_OR_RESTART, + "Left/Right to change bit-size" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EXACT, - "Left/Right to change value" -) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EXACT, + "Left/Right to change value" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_LT, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_LT, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_GT, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_GT, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_LTE, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_LTE, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_GTE, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_GTE, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQ, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQ, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_NEQ, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_NEQ, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQPLUS, - "Left/Right to change value" -) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQPLUS, + "Left/Right to change value" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQMINUS, - "Left/Right to change value" -) + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQMINUS, + "Left/Right to change value" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_ADD_MATCHES, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_ADD_MATCHES, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_VIEW_MATCHES, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_VIEW_MATCHES, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_CREATE_OPTION, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_CREATE_OPTION, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_DELETE_OPTION, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_DELETE_OPTION, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_ADD_NEW_TOP, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_ADD_NEW_TOP, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_ADD_NEW_BOTTOM, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_ADD_NEW_BOTTOM, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_DELETE_ALL, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_DELETE_ALL, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_RELOAD_CHEATS, - "" -) + MENU_ENUM_SUBLABEL_CHEAT_RELOAD_CHEATS, + "" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_BIG_ENDIAN, - "Big endian : 258 = 0x0102,\nLittle endian : 258 = 0x0201" - ) + MENU_ENUM_SUBLABEL_CHEAT_BIG_ENDIAN, + "Big endian : 258 = 0x0102,\nLittle endian : 258 = 0x0201" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, - "Sets log level for cores. If a log level issued by a core is below this value, it is ignored." - ) + MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, + "Sets log level for cores. If a log level issued by a core is below this value, it is ignored." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PERFCNT_ENABLE, - "Enable performance counters for RetroArch (and cores)." - ) + MENU_ENUM_SUBLABEL_PERFCNT_ENABLE, + "Enable performance counters for RetroArch (and cores)." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatically makes a savestate at the end of RetroArch's runtime. RetroArch will automatically load this savestate if 'Auto Load State' is enabled." - ) + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, + "Automatically makes a savestate at the end of RetroArch's runtime. RetroArch will automatically load this savestate if 'Auto Load State' is enabled." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, - "Automatically load the auto save state on startup." - ) + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, + "Automatically load the auto save state on startup." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE, - "Show thumbnails of save states inside the menu." - ) + MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE, + "Show thumbnails of save states inside the menu." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, - "Autosaves the non-volatile Save RAM at a regular interval. This is disabled by default unless set otherwise. The interval is measured in seconds. A value of 0 disables autosave." - ) + MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, + "Autosaves the non-volatile Save RAM at a regular interval. This is disabled by default unless set otherwise. The interval is measured in seconds. A value of 0 disables autosave." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, - "If enabled, overrides the input binds with the remapped binds set for the current core." - ) + MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, + "If enabled, overrides the input binds with the remapped binds set for the current core." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_AUTODETECT_ENABLE, - "Enable input auto-detection. Will attempt to autoconfigure joypads, Plug-and-Play style." - ) + MENU_ENUM_SUBLABEL_INPUT_AUTODETECT_ENABLE, + "Enable input auto-detection. Will attempt to autoconfigure joypads, Plug-and-Play style." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_INPUT_SWAP_OK_CANCEL, - "Swap buttons for OK/Cancel. Disabled is the Japanese button orientation, enabled is the western orientation." - ) + MENU_ENUM_SUBLABEL_MENU_INPUT_SWAP_OK_CANCEL, + "Swap buttons for OK/Cancel. Disabled is the Japanese button orientation, enabled is the western orientation." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "If disabled, the content will keep running in the background when RetroArch's menu is toggled." - ) + MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, + "If disabled, the content will keep running in the background when RetroArch's menu is toggled." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_DRIVER, - "Video driver to use." - ) + MENU_ENUM_SUBLABEL_VIDEO_DRIVER, + "Video driver to use." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_DRIVER, - "Audio driver to use." - ) + MENU_ENUM_SUBLABEL_AUDIO_DRIVER, + "Audio driver to use." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DRIVER, - "Input driver to use. Depending on the video driver, it might force a different input driver." - ) + MENU_ENUM_SUBLABEL_INPUT_DRIVER, + "Input driver to use. Depending on the video driver, it might force a different input driver." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, - "Joypad driver to use." - ) + MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, + "Joypad driver to use." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_DRIVER, - "Audio resampler driver to use." - ) + MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_DRIVER, + "Audio resampler driver to use." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CAMERA_DRIVER, - "Camera driver to use." - ) + MENU_ENUM_SUBLABEL_CAMERA_DRIVER, + "Camera driver to use." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LOCATION_DRIVER, - "Location driver to use." - ) + MENU_ENUM_SUBLABEL_LOCATION_DRIVER, + "Location driver to use." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_DRIVER, - "Menu driver to use." - ) + MENU_ENUM_SUBLABEL_MENU_DRIVER, + "Menu driver to use." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RECORD_DRIVER, - "Record driver to use." - ) + MENU_ENUM_SUBLABEL_RECORD_DRIVER, + "Record driver to use." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MIDI_DRIVER, - "MIDI driver to use." - ) + MENU_ENUM_SUBLABEL_MIDI_DRIVER, + "MIDI driver to use." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_WIFI_DRIVER, - "WiFi driver to use." - ) + MENU_ENUM_SUBLABEL_WIFI_DRIVER, + "WiFi driver to use." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, - "Filter files being shown in filebrowser by supported extensions." - ) + MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Filter files being shown in filebrowser by supported extensions." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_WALLPAPER, - "Select an image to set as menu wallpaper." - ) + MENU_ENUM_SUBLABEL_MENU_WALLPAPER, + "Select an image to set as menu wallpaper." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER, - "Dynamically load a new wallpaper depending on context." - ) + MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER, + "Dynamically load a new wallpaper depending on context." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_DEVICE, - "Override the default audio device the audio driver uses. This is driver dependent." - ) + MENU_ENUM_SUBLABEL_AUDIO_DEVICE, + "Override the default audio device the audio driver uses. This is driver dependent." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN, - "Audio DSP plugin that processes audio before it's sent to the driver." - ) + MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN, + "Audio DSP plugin that processes audio before it's sent to the driver." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_OUTPUT_RATE, - "Audio output sample rate." - ) + MENU_ENUM_SUBLABEL_AUDIO_OUTPUT_RATE, + "Audio output sample rate." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, - "Opacity of all UI elements of the overlay." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OVERLAY_SCALE, - "Scale of all UI elements of the overlay." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ENABLE, - "Enable the overlay." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OVERLAY_PRESET, - "Select an overlay from the file browser." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, - "The address of the host to connect to." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT, - "The port of the host IP address. Can be either a TCP or UDP port." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, - "The password for connecting to the netplay host. Used only in host mode." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, - "Whether to announce netplay games publicly. If unset, clients must manually connect rather than using the public lobby." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, - "The password for connecting to the netplay host with only spectator privileges. Used only in host mode." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_START_AS_SPECTATOR, - "Whether to start netplay in spectator mode." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_SLAVES, - "Whether to allow connections in slave mode. Slave-mode clients require very little processing power on either side, but will suffer significantly from network latency." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_REQUIRE_SLAVES, - "Whether to disallow connections not in slave mode. Not recommended except for very fast networks with very weak machines." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_STATELESS_MODE, - "Whether to run netplay in a mode not requiring save states. If set to true, a very fast network is required, but no rewinding is performed, so there will be no netplay jitter." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_CHECK_FRAMES, - "The frequency in frames with which netplay will verify that the host and client are in sync." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_NAT_TRAVERSAL, - "When hosting, attempt to listen for connections from the public Internet, using UPnP or similar technologies to escape LANs." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, - "Enable stdin command interface." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_MOUSE_ENABLE, - "Enable mouse controls inside the menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_POINTER_ENABLE, - "Enable touch controls inside the menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_THUMBNAILS, - "Type of thumbnail to display." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, - "Type of thumbnail to display at the left." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_XMB_VERTICAL_THUMBNAILS, - "Display the left thumbnail under the right one, on the right side of the screen.") -MSG_HASH( - MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE, - "Shows current date and/or time inside the menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE, - "Shows current battery level inside the menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NAVIGATION_WRAPAROUND, - "Wrap-around to beginning and/or end if boundary of list is reached horizontally or vertically." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, - "Enables netplay in host (server) mode." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_CLIENT, - "Enables netplay in client mode.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_DISCONNECT, - "Disconnects an active Netplay connection.") -MSG_HASH(MENU_ENUM_SUBLABEL_SCAN_DIRECTORY, - "Scans a directory for compatible files and add them to the collection.") -MSG_HASH(MENU_ENUM_SUBLABEL_SCAN_FILE, - "Scans a compatible file and add it to the collection.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SWAP_INTERVAL, - "Uses a custom swap interval for Vsync. Set this to effectively halve monitor refresh rate." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_SORT_SAVEFILES_ENABLE, - "Sort save files in folders named after the core used." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE, - "Sort save states in folders named after the core used." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_REQUEST_DEVICE_I, - "Request to play with the given input device.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, - "URL to core updater directory on the Libretro buildbot.") -MSG_HASH(MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL, - "URL to assets updater directory on the Libretro buildbot.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, - "After downloading, automatically extract files contained in the downloaded archives." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, - "Scan for new rooms.") -MSG_HASH(MENU_ENUM_SUBLABEL_DELETE_ENTRY, - "Remove this entry from the collection.") -MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION, - "View more information about the content.") -MSG_HASH(MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES, - "Add the entry to your favorites.") -MSG_HASH(MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES_PLAYLIST, - "Add the entry to your favorites.") -MSG_HASH(MENU_ENUM_SUBLABEL_RUN, - "Start the content.") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, - "Adjusts filebrowser settings.") -MSG_HASH( - MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, - "Enable customized controls by default at startup." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, - "Enable customized configuration by default at startup." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, - "Enable customized core options by default at startup.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_ENABLE, - "Shows current core name inside menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_DATABASE_MANAGER, - "View databases.") -MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_MANAGER, - "View previous searches.") -MSG_HASH(MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, - "Captures an image of the screen.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Closes the current content. Any unsaved changes might be lost." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_STATE, - "Load a saved state from the currently selected slot.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_STATE, - "Save a state to the currently selected slot.") -MSG_HASH(MENU_ENUM_SUBLABEL_RESUME, - "Resume the currently running content and leave the Quick Menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Resume the currently running content and leave the Quick Menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_STATE_SLOT, - "Changes the currently selected state slot.") -MSG_HASH(MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE, - "If a state was loaded, content will go back to the state prior to loading.") -MSG_HASH(MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, - "If a state was overwritten, it will roll back to the previous save state.") -MSG_HASH( - MENU_ENUM_SUBLABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, - "RetroAchievements service. For more information, visit http://retroachievements.org" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, - "Manages currently configured accounts." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_META_REWIND, - "Manages rewind settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_DETAILS, - "Manages cheat details settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_SEARCH, - "Start or continue a cheat code search.") -MSG_HASH(MENU_ENUM_SUBLABEL_RESTART_CONTENT, - "Restarts the content from the beginning.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, - "Saves an override configuration file which will apply for all content loaded with this core. Will take precedence over the main configuration.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, - "Saves an override configuration file which will apply for all content loaded from the same directory as the current file. Will take precedence over the main configuration.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, - "Saves an override configuration file which will apply for the current content only. Will take precedence over the main configuration.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, - "Set up cheat codes.") -MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_OPTIONS, - "Set up shaders to visually augment the image.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Change the controls for the currently running content.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Change the options for the currently running content.") -MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, - "Show advanced settings for power users (hidden by default).") -MSG_HASH(MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, - "Perform tasks on a separate thread.") -MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, - "Allow the user to remove entries from collections.") -MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, - "Sets the System directory. Cores can query for this directory to load BIOSes, system-specific configs, etc.") -MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, - "Sets start directory for the filebrowser.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_DIR, - "Usually set by developers who bundle libretro/RetroArch apps to point to assets." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPERS_DIRECTORY, - "Directory to store wallpapers dynamically loaded by the menu depending on context.") -MSG_HASH(MENU_ENUM_SUBLABEL_THUMBNAILS_DIRECTORY, - "Supplementary thumbnails (boxarts/misc. images, etc.) are stored here." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, - "Sets start directory for menu configuration browser.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, - "The number of frames of input latency for netplay to use to hide network latency. Reduces jitter and makes netplay less CPU-intensive, at the expense of noticeable input lag.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, - "The range of frames of input latency that may be used to hide network latency. Reduces jitter and makes netplay less CPU-intensive, at the expense of unpredictable input lag.") -MSG_HASH(MENU_ENUM_SUBLABEL_DISK_CYCLE_TRAY_STATUS, - "Cycle the current disk. If the disk is inserted, it will eject the disk. If the disk has not been inserted, it will be inserted. ") -MSG_HASH(MENU_ENUM_SUBLABEL_DISK_INDEX, - "Change the disk index.") -MSG_HASH(MENU_ENUM_SUBLABEL_DISK_OPTIONS, - "Disk image management.") -MSG_HASH(MENU_ENUM_SUBLABEL_DISK_IMAGE_APPEND, - "Select a disk image to insert.") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_ENUM_THROTTLE_FRAMERATE, - "Makes sure the framerate is capped while inside the menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_VRR_RUNLOOP_ENABLE, - "No deviation from core requested timing. Use for Variable Refresh Rate screens, G-Sync, FreeSync.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_LAYOUT, - "Select a different layout for the XMB interface.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_THEME, - "Select a different theme for the icon. Changes will take effect after you restart the program.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE, - "Enable drop shadows for all icons. This will have a minor performance hit.") -MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME, - "Select a different background color gradient theme.") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY, - "Modify the opacity of the background wallpaper.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_MENU_COLOR_THEME, - "Select a different background color gradient theme.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, - "Select an animated background effect. Can be GPU-intensive depending on the effect. If performance is unsatisfactory, either turn this off or revert to a simpler effect.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_FONT, - "Select a different main font to be used by the menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_FAVORITES, - "Show the favorites tab inside the main menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, - "Show the image tab inside the main menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, - "Show the music tab inside the main menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, - "Show the video tab inside the main menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, - "Show the netplay tab inside the main menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS, - "Show the settings tab inside the main menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_HISTORY, - "Show the recent history tab inside the main menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, - "Show the import content tab inside the main menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Show playlist tabs inside the main menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, - "Show startup screen in menu. This is automatically set to false after the program starts for the first time.") -MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, - "Modify the opacity of the header graphic.") -MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, - "Modify the opacity of the footer graphic.") -MSG_HASH(MENU_ENUM_SUBLABEL_DPI_OVERRIDE_ENABLE, - "The menu normally scales itself dynamically. If you want to set a specific scaling size instead, enable this.") -MSG_HASH(MENU_ENUM_SUBLABEL_DPI_OVERRIDE_VALUE, - "Set the custom scaling size here. NOTE: You have to enable 'DPI Override' for this scaling size to take effect.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, - "Save all downloaded files to this directory.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_REMAPPING_DIRECTORY, - "Save all remapped controls to this directory.") -MSG_HASH(MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, - "Directory where the program searches for content/cores.") -MSG_HASH(MENU_ENUM_SUBLABEL_LIBRETRO_INFO_PATH, - "Application/core information files are stored here.") -MSG_HASH(MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, - "If a joypad is plugged in, that joypad will be autoconfigured if a config file corresponding to it is present inside this directory.") -MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_DIRECTORY, - "Save all collections to this directory.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, - "If set to a directory, content which is temporarily extracted (e.g. from archives) will be extracted to this directory." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_DIRECTORY, - "Saved queries are stored to this directory.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, - "Databases are stored to this directory." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, - "This location is queried by default when menu interfaces try to look for loadable assets, etc." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_SAVEFILE_DIRECTORY, - "Save all save files to this directory. If not set, will try to save inside the content file's working directory.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVESTATE_DIRECTORY, - "Save all save states to this directory. If not set, will try to save inside the content file's working directory.") -MSG_HASH(MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, - "Directory to dump screenshots to.") -MSG_HASH(MENU_ENUM_SUBLABEL_OVERLAY_DIRECTORY, - "Defines a directory where overlays are kept for easy access.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_DATABASE_PATH, - "Cheat files are kept here." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_FILTER_DIR, - "Directory where audio DSP filter files are kept." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FILTER_DIR, - "Directory where CPU-based video filter files are kept." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_DIR, - "Defines a directory where GPU-based video shader files are kept for easy access.") -MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_OUTPUT_DIRECTORY, - "Recordings will be dumped to this directory.") -MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_CONFIG_DIRECTORY, - "Recording configurations will be kept here.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_PATH, - "Select a different font for onscreen notifications.") -MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_APPLY_CHANGES, - "Changes to the shader configuration will take effect immediately. Use this if you changed the amount of shader passes, filtering, FBO scale, etc.") -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_NUM_PASSES, - "Increase or decrease the amount of shader pipeline passes. You can bind a separate shader to each pipeline pass and configure its scale and filtering." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET, - "Load a shader preset. The shader pipeline will be automatically set-up.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_AS, - "Save the current shader settings as a new shader preset.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, - "Save the current shader settings as the default settings for this application/core.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_PARENT, - "Save the current shader settings as the default settings for all files in the current content directory.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, - "Save the current shader settings as the default settings for the content.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, - "Modifies the current shader directly. Changes will not be saved to the preset file.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PARAMETERS, - "Modifies the shader preset itself currently used in the menu.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, - "Increase or decrease the amount of cheats." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_CHEAT_APPLY_CHANGES, - "Cheat changes will take effect immediately.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEAT_START_SEARCH, - "Start search for a new cheat. Number of bits can be changed.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEAT_CONTINUE_SEARCH, - "Continue search for a new cheat.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, - "Load a cheat file and replace existing cheats." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD_APPEND, - "Load a cheat file and append to existing cheats." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_FILE_SAVE_AS, - "Save current cheats as a save file." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SETTINGS, - "Quickly access all relevant in-game settings.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INFORMATION, - "View information pertaining to the application/core.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO, - "Floating point value for video aspect ratio (width / height), used if the Aspect Ratio is set to 'Config'.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "Custom viewport height that is used if the Aspect Ratio is set to 'Custom'.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "Custom viewport width that is used if the Aspect Ratio is set to 'Custom'.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, - "Custom viewport offset used for defining the X-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, - "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use Relay Server") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, - "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER, - "Relay Server Location") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_MITM_SERVER, - "Choose a specific relay server to use. Geographically closer locations tend to have lower latency.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, - "Add to mixer") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_PLAY, - "Add to mixer and play") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION, - "Add to mixer") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY, - "Add to mixer and play") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, - "Filter by current core") -MSG_HASH( - MSG_AUDIO_MIXER_VOLUME, - "Global audio mixer volume" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, - "Global audio mixer volume (in dB). 0 dB is normal volume, and no gain is applied." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, - "Audio Mixer Volume Level (dB)" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, - "Audio Mixer Mute" - ) -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, - "Mute/unmute mixer audio.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_ONLINE_UPDATER, - "Show Online Updater") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, - "Show/hide the 'Online Updater' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_VIEWS_SETTINGS, - "Views") -MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_VIEWS_SETTINGS, - "Show or hide elements on the menu screen." - ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, - "Show Core Updater") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, - "Show/hide the ability to update cores (and core info files).") -MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, - "Preparing for content scan...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, - "Delete core") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, - "Remove this core from disk.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, - "Framebuffer Opacity") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, - "Modify the opacity of the framebuffer.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, - "Favorites") -MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, - "Content which you have added to 'Favorites' will appear here.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, - "Music") -MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, - "Music which has been previously played will appear here.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, - "Image") -MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, - "Images which have been previously viewed will appear here.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, - "Video") -MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, - "Videos which have been previously played will appear here.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, - "Menu Icons") -MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, - "Enable/disable the menu icons shown at the lefthand side of the menu entries.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MAIN_MENU_ENABLE_SETTINGS, - "Enable Settings Tab") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS_PASSWORD, - "Set Password For Enabling Settings Tab") -MSG_HASH(MSG_INPUT_ENABLE_SETTINGS_PASSWORD, - "Enter Password") -MSG_HASH(MSG_INPUT_ENABLE_SETTINGS_PASSWORD_OK, - "Password correct.") -MSG_HASH(MSG_INPUT_ENABLE_SETTINGS_PASSWORD_NOK, - "Password incorrect.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_MAIN_MENU_ENABLE_SETTINGS, - "Enables the Settings tab. A restart is required for the tab to appear.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS_PASSWORD, - "Supplying a password when hiding the settings tab makes it possible to later restore it from the menu, by going to the Main Menu tab, selecting Enable Settings Tab and entering the password.") -MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, - "Allow the user to rename entries in collections.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, - "Allow to rename entries") -MSG_HASH(MENU_ENUM_SUBLABEL_RENAME_ENTRY, - "Rename the title of the entry.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RENAME_ENTRY, - "Rename") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CORE, - "Show Load Core") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CORE, - "Show/hide the 'Load Core' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CONTENT, - "Show Load Content") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CONTENT, - "Show/hide the 'Load Content' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_INFORMATION, - "Show Information") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_INFORMATION, - "Show/hide the 'Information' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CONFIGURATIONS, - "Show Configurations") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CONFIGURATIONS, - "Show/hide the 'Configurations' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_HELP, - "Show Help") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_HELP, - "Show/hide the 'Help' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_QUIT_RETROARCH, - "Show Quit RetroArch") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_QUIT_RETROARCH, - "Show/hide the 'Quit RetroArch' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_REBOOT, - "Show Reboot") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_REBOOT, - "Show/hide the 'Reboot' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_SHUTDOWN, - "Show Shutdown") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_SHUTDOWN, - "Show/hide the 'Shutdown' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_VIEWS_SETTINGS, - "Quick Menu") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_VIEWS_SETTINGS, - "Show or hide elements on the Quick Menu screen.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_TAKE_SCREENSHOT, - "Show Take Screenshot") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_TAKE_SCREENSHOT, - "Show/hide the 'Take Screenshot' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_LOAD_STATE, - "Show Save/Load State") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, - "Show/hide the options for saving/loading state.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, - "Show Undo Save/Load State") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, - "Show/hide the options for undoing save/load state.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_FAVORITES, - "Show Add to Favorites") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, - "Show/hide the 'Add to Favorites' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_OPTIONS, - "Show Options") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_OPTIONS, - "Show/hide the 'Options' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CONTROLS, - "Show Controls") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CONTROLS, - "Show/hide the 'Controls' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CHEATS, - "Show Cheats") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CHEATS, - "Show/hide the 'Cheats' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SHADERS, - "Show Shaders") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SHADERS, - "Show/hide the 'Shaders' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, - "Show Save Core Overrides") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, - "Show/hide the 'Save Core Overrides' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, - "Show Save Game Overrides") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, - "Show/hide the 'Save Game Overrides' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_INFORMATION, - "Show Information") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_INFORMATION, - "Show/hide the 'Information' option.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_ENABLE, - "Notification Background Enable") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_RED, - "Notification Background Red Color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_GREEN, - "Notification Background Green Color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_BLUE, - "Notification Background Blue Color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_OPACITY, - "Notification Background Opacity") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_DISABLE_KIOSK_MODE, - "Disable Kiosk Mode") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_DISABLE_KIOSK_MODE, - "Disables kiosk mode. A restart is required for the change to take full effect.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_ENABLE_KIOSK_MODE, - "Enable Kiosk Mode") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_ENABLE_KIOSK_MODE, - "Protects the setup by hiding all configuration related settings.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_KIOSK_MODE_PASSWORD, - "Set Password For Disabling Kiosk Mode") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_KIOSK_MODE_PASSWORD, - "Supplying a password when enabling kiosk mode makes it possible to later disable it from the menu, by going to the Main Menu, selecting Disable Kiosk Mode and entering the password.") -MSG_HASH(MSG_INPUT_KIOSK_MODE_PASSWORD, - "Enter Password") -MSG_HASH(MSG_INPUT_KIOSK_MODE_PASSWORD_OK, - "Password correct.") -MSG_HASH(MSG_INPUT_KIOSK_MODE_PASSWORD_NOK, - "Password incorrect.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_RED, - "Notification Red Color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_GREEN, - "Notification Green Color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_BLUE, - "Notification Blue Color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAMECOUNT_SHOW, - "Show frame count on FPS display") -MSG_HASH(MSG_CONFIG_OVERRIDE_LOADED, - "Configuration override loaded.") -MSG_HASH(MSG_GAME_REMAP_FILE_LOADED, - "Game remap file loaded.") -MSG_HASH(MSG_CORE_REMAP_FILE_LOADED, - "Core remap file loaded.") -MSG_HASH(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "RunAhead has been disabled because this core does not support save states.") -MSG_HASH(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, - "Failed to save state. RunAhead has been disabled.") -MSG_HASH(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE, - "Failed to load state. RunAhead has been disabled.") -MSG_HASH(MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE, - "Failed to create second instance. RunAhead will now use only one instance.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, - "Automatically add content to playlist") -MSG_HASH(MENU_ENUM_SUBLABEL_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, - "Automatically scans loaded content so they appear inside playlists.") -MSG_HASH(MSG_SCANNING_OF_FILE_FINISHED, - "Scanning of file finished") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_OPACITY, - "Window Opacity") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_QUALITY, - "Audio Resampler Quality") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_QUALITY, - "Lower this value to favor performance/lower latency over audio quality, increase if you want better audio quality at the expense of performance/lower latency.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_WATCH_FOR_CHANGES, - "Watch shader files for changes") -MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, - "Auto-apply changes made to shader files on disk.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SHOW_DECORATIONS, - "Show Window Decorations") -MSG_HASH(MENU_ENUM_LABEL_VALUE_STATISTICS_SHOW, - "Display Statistics") -MSG_HASH(MENU_ENUM_SUBLABEL_STATISTICS_SHOW, - "Show onscreen technical statistics.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_ENABLE, - "Enable border filler") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, - "Enable border filler thickness") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, - "Enable background filler thickness") -MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, - "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, - "CRT SwitchRes") -MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, - "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, - "CRT Super Resolution") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, - "Show Rewind Settings") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, - "Show/hide the Rewind options.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_LATENCY, - "Show/hide the Latency options.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_LATENCY, - "Show Latency Settings") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_OVERLAYS, - "Show/hide the Overlay options.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_OVERLAYS, - "Show Overlay Settings") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE_MENU, - "Enable menu audio") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_ENABLE_MENU, - "Enable or disable menu sound.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_SETTINGS, - "Mixer Settings") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_SETTINGS, - "View and/or modify audio mixer settings.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_INFO, - "Info") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_FILE, - "&File") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_LOAD_CORE, - "&Load Core...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_UNLOAD_CORE, - "&Unload Core") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_EXIT, - "E&xit") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT, - "&Edit") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT_SEARCH, - "&Search") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW, - "&View") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_CLOSED_DOCKS, - "Closed Docks") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_SHADER_PARAMS, - "Shader Parameters") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS, - "&Options...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS, - "Remember dock positions:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY, - "Remember window geometry:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB, - "Remember last content browser tab:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME, - "Theme:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK, - "Dark") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM, - "Custom...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE, - "Options") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_TOOLS, - "&Tools") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP, - "&Help") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT, - "About RetroArch") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_DOCUMENTATION, - "Documentation") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOAD_CUSTOM_CORE, - "Load Custom Core...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOAD_CORE, - "Load Core") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOADING_CORE, - "Loading Core...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_NAME, - "Name") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CORE_VERSION, - "Version") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_TAB_PLAYLISTS, - "Playlists") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER, - "File Browser") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_TOP, - "Top") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_UP, - "Up") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER, - "Content Browser") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_BOXART, - "Boxart") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_SCREENSHOT, - "Screenshot") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, - "Title Screen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, - "All Playlists") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CORE, - "Core") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CORE_INFO, - "Core Info") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CORE_SELECTION_ASK, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_INFORMATION, - "Information") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_WARNING, - "Warning") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ERROR, - "Error") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR, - "Network Error") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESTART_TO_TAKE_EFFECT, - "Please restart the program for the changes to take effect.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOG, - "Log") + MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, + "Opacity of all UI elements of the overlay." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_SCALE, + "Scale of all UI elements of the overlay." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ENABLE, + "Enable the overlay." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_PRESET, + "Select an overlay from the file browser." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, + "The address of the host to connect to." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT, + "The port of the host IP address. Can be either a TCP or UDP port." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, + "The password for connecting to the netplay host. Used only in host mode." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, + "Whether to announce netplay games publicly. If unset, clients must manually connect rather than using the public lobby." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, + "The password for connecting to the netplay host with only spectator privileges. Used only in host mode." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_START_AS_SPECTATOR, + "Whether to start netplay in spectator mode." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_SLAVES, + "Whether to allow connections in slave mode. Slave-mode clients require very little processing power on either side, but will suffer significantly from network latency." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_REQUIRE_SLAVES, + "Whether to disallow connections not in slave mode. Not recommended except for very fast networks with very weak machines." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_STATELESS_MODE, + "Whether to run netplay in a mode not requiring save states. If set to true, a very fast network is required, but no rewinding is performed, so there will be no netplay jitter." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_CHECK_FRAMES, + "The frequency in frames with which netplay will verify that the host and client are in sync." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_NAT_TRAVERSAL, + "When hosting, attempt to listen for connections from the public Internet, using UPnP or similar technologies to escape LANs." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, + "Enable stdin command interface." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MOUSE_ENABLE, + "Enable mouse controls inside the menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_POINTER_ENABLE, + "Enable touch controls inside the menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_THUMBNAILS, + "Type of thumbnail to display." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, + "Type of thumbnail to display at the left." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_VERTICAL_THUMBNAILS, + "Display the left thumbnail under the right one, on the right side of the screen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE, + "Shows current date and/or time inside the menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE, + "Shows current battery level inside the menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NAVIGATION_WRAPAROUND, + "Wrap-around to beginning and/or end if boundary of list is reached horizontally or vertically." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, + "Enables netplay in host (server) mode." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_CLIENT, + "Enables netplay in client mode." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_DISCONNECT, + "Disconnects an active Netplay connection." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCAN_DIRECTORY, + "Scans a directory for compatible files and add them to the collection." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCAN_FILE, + "Scans a compatible file and add it to the collection." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SWAP_INTERVAL, + "Uses a custom swap interval for Vsync. Set this to effectively halve monitor refresh rate." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SORT_SAVEFILES_ENABLE, + "Sort save files in folders named after the core used." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE, + "Sort save states in folders named after the core used." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_REQUEST_DEVICE_I, + "Request to play with the given input device." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, + "URL to core updater directory on the Libretro buildbot." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL, + "URL to assets updater directory on the Libretro buildbot." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "After downloading, automatically extract files contained in the downloaded archives." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, + "Scan for new rooms." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DELETE_ENTRY, + "Remove this entry from the collection." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INFORMATION, + "View more information about the content." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES, + "Add the entry to your favorites." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES_PLAYLIST, + "Add the entry to your favorites." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN, + "Start the content." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, + "Adjusts filebrowser settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, + "Enable customized controls by default at startup." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, + "Enable customized configuration by default at startup." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, + "Enable customized core options by default at startup." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_ENABLE, + "Shows current core name inside menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DATABASE_MANAGER, + "View databases." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CURSOR_MANAGER, + "View previous searches." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, + "Captures an image of the screen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOSE_CONTENT, + "Closes the current content. Any unsaved changes might be lost." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOAD_STATE, + "Load a saved state from the currently selected slot." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_STATE, + "Save a state to the currently selected slot." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESUME, + "Resume the currently running content and leave the Quick Menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESUME_CONTENT, + "Resume the currently running content and leave the Quick Menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STATE_SLOT, + "Changes the currently selected state slot." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE, + "If a state was loaded, content will go back to the state prior to loading." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, + "If a state was overwritten, it will roll back to the previous save state." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, + "RetroAchievements service. For more information, visit http://retroachievements.org" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, + "Manages currently configured accounts." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_REWIND, + "Manages rewind settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_DETAILS, + "Manages cheat details settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_SEARCH, + "Start or continue a cheat code search." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESTART_CONTENT, + "Restarts the content from the beginning." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Saves an override configuration file which will apply for all content loaded with this core. Will take precedence over the main configuration." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, + "Saves an override configuration file which will apply for all content loaded from the same directory as the current file. Will take precedence over the main configuration." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, + "Saves an override configuration file which will apply for the current content only. Will take precedence over the main configuration." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, + "Set up cheat codes." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHADER_OPTIONS, + "Set up shaders to visually augment the image." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, + "Change the controls for the currently running content." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_OPTIONS, + "Change the options for the currently running content." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, + "Show advanced settings for power users (hidden by default)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, + "Perform tasks on a separate thread." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, + "Allow the user to remove entries from collections." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, + "Sets the System directory. Cores can query for this directory to load BIOSes, system-specific configs, etc." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, + "Sets start directory for the filebrowser." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_DIR, + "Usually set by developers who bundle libretro/RetroArch apps to point to assets." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPERS_DIRECTORY, + "Directory to store wallpapers dynamically loaded by the menu depending on context." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_THUMBNAILS_DIRECTORY, + "Supplementary thumbnails (boxarts/misc. images, etc.) are stored here." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, + "Sets start directory for menu configuration browser." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "The number of frames of input latency for netplay to use to hide network latency. Reduces jitter and makes netplay less CPU-intensive, at the expense of noticeable input lag." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "The range of frames of input latency that may be used to hide network latency. Reduces jitter and makes netplay less CPU-intensive, at the expense of unpredictable input lag." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISK_CYCLE_TRAY_STATUS, + "Cycle the current disk. If the disk is inserted, it will eject the disk. If the disk has not been inserted, it will be inserted. " + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISK_INDEX, + "Change the disk index." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISK_OPTIONS, + "Disk image management." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISK_IMAGE_APPEND, + "Select a disk image to insert." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_ENUM_THROTTLE_FRAMERATE, + "Makes sure the framerate is capped while inside the menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VRR_RUNLOOP_ENABLE, + "No deviation from core requested timing. Use for Variable Refresh Rate screens, G-Sync, FreeSync." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_LAYOUT, + "Select a different layout for the XMB interface." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_THEME, + "Select a different theme for the icon. Changes will take effect after you restart the program." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE, + "Enable drop shadows for all icons. This will have a minor performance hit." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME, + "Select a different background color gradient theme." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY, + "Modify the opacity of the background wallpaper." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_MENU_COLOR_THEME, + "Select a different background color gradient theme." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, + "Select an animated background effect. Can be GPU-intensive depending on the effect. If performance is unsatisfactory, either turn this off or revert to a simpler effect." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_FONT, + "Select a different main font to be used by the menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_FAVORITES, + "Show the favorites tab inside the main menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, + "Show the image tab inside the main menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, + "Show the music tab inside the main menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, + "Show the video tab inside the main menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, + "Show the netplay tab inside the main menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS, + "Show the settings tab inside the main menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_HISTORY, + "Show the recent history tab inside the main menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, + "Show the import content tab inside the main menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, + "Show playlist tabs inside the main menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, + "Show startup screen in menu. This is automatically set to false after the program starts for the first time." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, + "Modify the opacity of the header graphic." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, + "Modify the opacity of the footer graphic." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DPI_OVERRIDE_ENABLE, + "The menu normally scales itself dynamically. If you want to set a specific scaling size instead, enable this." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DPI_OVERRIDE_VALUE, + "Set the custom scaling size here. NOTE: You have to enable 'DPI Override' for this scaling size to take effect." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, + "Save all downloaded files to this directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_REMAPPING_DIRECTORY, + "Save all remapped controls to this directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, + "Directory where the program searches for content/cores." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LIBRETRO_INFO_PATH, + "Application/core information files are stored here." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, + "If a joypad is plugged in, that joypad will be autoconfigured if a config file corresponding to it is present inside this directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_DIRECTORY, + "Save all collections to this directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, + "If set to a directory, content which is temporarily extracted (e.g. from archives) will be extracted to this directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CURSOR_DIRECTORY, + "Saved queries are stored to this directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, + "Databases are stored to this directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, + "This location is queried by default when menu interfaces try to look for loadable assets, etc." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVEFILE_DIRECTORY, + "Save all save files to this directory. If not set, will try to save inside the content file's working directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_DIRECTORY, + "Save all save states to this directory. If not set, will try to save inside the content file's working directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, + "Directory to dump screenshots to." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_DIRECTORY, + "Defines a directory where overlays are kept for easy access." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_DATABASE_PATH, + "Cheat files are kept here." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_FILTER_DIR, + "Directory where audio DSP filter files are kept." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FILTER_DIR, + "Directory where CPU-based video filter files are kept." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_DIR, + "Defines a directory where GPU-based video shader files are kept for easy access." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORDING_OUTPUT_DIRECTORY, + "Recordings will be dumped to this directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORDING_CONFIG_DIRECTORY, + "Recording configurations will be kept here." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FONT_PATH, + "Select a different font for onscreen notifications." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHADER_APPLY_CHANGES, + "Changes to the shader configuration will take effect immediately. Use this if you changed the amount of shader passes, filtering, FBO scale, etc." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_NUM_PASSES, + "Increase or decrease the amount of shader pipeline passes. You can bind a separate shader to each pipeline pass and configure its scale and filtering." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET, + "Load a shader preset. The shader pipeline will be automatically set-up." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_AS, + "Save the current shader settings as a new shader preset." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, + "Save the current shader settings as the default settings for this application/core." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_PARENT, + "Save the current shader settings as the default settings for all files in the current content directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, + "Save the current shader settings as the default settings for the content." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, + "Modifies the current shader directly. Changes will not be saved to the preset file." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PARAMETERS, + "Modifies the shader preset itself currently used in the menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, + "Increase or decrease the amount of cheats." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_APPLY_CHANGES, + "Cheat changes will take effect immediately." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_START_SEARCH, + "Start search for a new cheat. Number of bits can be changed." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_CONTINUE_SEARCH, + "Continue search for a new cheat." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, + "Load a cheat file and replace existing cheats." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD_APPEND, + "Load a cheat file and append to existing cheats." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_SAVE_AS, + "Save current cheats as a save file." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SETTINGS, + "Quickly access all relevant in-game settings." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INFORMATION, + "View information pertaining to the application/core." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO, + "Floating point value for video aspect ratio (width / height), used if the Aspect Ratio is set to 'Config'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, + "Custom viewport height that is used if the Aspect Ratio is set to 'Custom'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, + "Custom viewport width that is used if the Aspect Ratio is set to 'Custom'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, + "Custom viewport offset used for defining the X-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, + "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, + "Use Relay Server" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, + "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER, + "Relay Server Location" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_MITM_SERVER, + "Choose a specific relay server to use. Geographically closer locations tend to have lower latency." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, + "Add to mixer" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_PLAY, + "Add to mixer and play" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION, + "Add to mixer" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY, + "Add to mixer and play" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "Filter by current core" + ) +MSG_HASH( + MSG_AUDIO_MIXER_VOLUME, + "Global audio mixer volume" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, + "Global audio mixer volume (in dB). 0 dB is normal volume, and no gain is applied." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, + "Audio Mixer Volume Level (dB)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, + "Audio Mixer Mute" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, + "Mute/unmute mixer audio." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_ONLINE_UPDATER, + "Show Online Updater" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, + "Show/hide the 'Online Updater' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_VIEWS_SETTINGS, + "Views" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_VIEWS_SETTINGS, + "Show or hide elements on the menu screen." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, + "Show Core Updater" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, + "Show/hide the ability to update cores (and core info files)." + ) +MSG_HASH( + MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparing for content scan..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MAIN_MENU_ENABLE_SETTINGS, + "Enable Settings Tab" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS_PASSWORD, + "Set Password For Enabling Settings Tab" + ) +MSG_HASH( + MSG_INPUT_ENABLE_SETTINGS_PASSWORD, + "Enter Password" + ) +MSG_HASH( + MSG_INPUT_ENABLE_SETTINGS_PASSWORD_OK, + "Password correct." + ) +MSG_HASH( + MSG_INPUT_ENABLE_SETTINGS_PASSWORD_NOK, + "Password incorrect." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_MAIN_MENU_ENABLE_SETTINGS, + "Enables the Settings tab. A restart is required for the tab to appear." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS_PASSWORD, + "Supplying a password when hiding the settings tab makes it possible to later restore it from the menu, by going to the Main Menu tab, selecting Enable Settings Tab and entering the password." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, + "Allow the user to rename entries in collections." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Allow to rename entries" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RENAME_ENTRY, + "Rename the title of the entry." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RENAME_ENTRY, + "Rename" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CORE, + "Show Load Core" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CORE, + "Show/hide the 'Load Core' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CONTENT, + "Show Load Content" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CONTENT, + "Show/hide the 'Load Content' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_INFORMATION, + "Show Information" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_INFORMATION, + "Show/hide the 'Information' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_CONFIGURATIONS, + "Show Configurations" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_CONFIGURATIONS, + "Show/hide the 'Configurations' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_HELP, + "Show Help" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_HELP, + "Show/hide the 'Help' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_QUIT_RETROARCH, + "Show Quit RetroArch" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_QUIT_RETROARCH, + "Show/hide the 'Quit RetroArch' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_REBOOT, + "Show Reboot" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_REBOOT, + "Show/hide the 'Reboot' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_SHUTDOWN, + "Show Shutdown" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_SHUTDOWN, + "Show/hide the 'Shutdown' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_VIEWS_SETTINGS, + "Quick Menu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_VIEWS_SETTINGS, + "Show or hide elements on the Quick Menu screen." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_TAKE_SCREENSHOT, + "Show Take Screenshot" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_TAKE_SCREENSHOT, + "Show/hide the 'Take Screenshot' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_LOAD_STATE, + "Show Save/Load State" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, + "Show/hide the options for saving/loading state." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, + "Show Undo Save/Load State" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, + "Show/hide the options for undoing save/load state." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_FAVORITES, + "Show Add to Favorites" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, + "Show/hide the 'Add to Favorites' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_OPTIONS, + "Show Options" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_OPTIONS, + "Show/hide the 'Options' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CONTROLS, + "Show Controls" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CONTROLS, + "Show/hide the 'Controls' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CHEATS, + "Show Cheats" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CHEATS, + "Show/hide the 'Cheats' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SHADERS, + "Show Shaders" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SHADERS, + "Show/hide the 'Shaders' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, + "Show Save Core Overrides" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, + "Show/hide the 'Save Core Overrides' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, + "Show Save Game Overrides" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, + "Show/hide the 'Save Game Overrides' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_INFORMATION, + "Show Information" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_INFORMATION, + "Show/hide the 'Information' option." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_ENABLE, + "Notification Background Enable" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_RED, + "Notification Background Red Color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_GREEN, + "Notification Background Green Color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_BLUE, + "Notification Background Blue Color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_OPACITY, + "Notification Background Opacity" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_DISABLE_KIOSK_MODE, + "Disable Kiosk Mode" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_DISABLE_KIOSK_MODE, + "Disables kiosk mode. A restart is required for the change to take full effect." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_ENABLE_KIOSK_MODE, + "Enable Kiosk Mode" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_ENABLE_KIOSK_MODE, + "Protects the setup by hiding all configuration related settings." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_KIOSK_MODE_PASSWORD, + "Set Password For Disabling Kiosk Mode" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_KIOSK_MODE_PASSWORD, + "Supplying a password when enabling kiosk mode makes it possible to later disable it from the menu, by going to the Main Menu, selecting Disable Kiosk Mode and entering the password." + ) +MSG_HASH( + MSG_INPUT_KIOSK_MODE_PASSWORD, + "Enter Password" + ) +MSG_HASH( + MSG_INPUT_KIOSK_MODE_PASSWORD_OK, + "Password correct." + ) +MSG_HASH( + MSG_INPUT_KIOSK_MODE_PASSWORD_NOK, + "Password incorrect." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_RED, + "Notification Red Color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_GREEN, + "Notification Green Color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_BLUE, + "Notification Blue Color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRAMECOUNT_SHOW, + "Show frame count on FPS display" + ) +MSG_HASH( + MSG_CONFIG_OVERRIDE_LOADED, + "Configuration override loaded." + ) +MSG_HASH( + MSG_GAME_REMAP_FILE_LOADED, + "Game remap file loaded." + ) +MSG_HASH( + MSG_CORE_REMAP_FILE_LOADED, + "Core remap file loaded." + ) +MSG_HASH( + MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, + "RunAhead has been disabled because this core does not support save states." + ) +MSG_HASH( + MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, + "Failed to save state. RunAhead has been disabled." + ) +MSG_HASH( + MSG_RUNAHEAD_FAILED_TO_LOAD_STATE, + "Failed to load state. RunAhead has been disabled." + ) +MSG_HASH( + MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE, + "Failed to create second instance. RunAhead will now use only one instance." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, + "Automatically add content to playlist" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, + "Automatically scans loaded content so they appear inside playlists." + ) +MSG_HASH( + MSG_SCANNING_OF_FILE_FINISHED, + "Scanning of file finished" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_OPACITY, + "Window Opacity" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_QUALITY, + "Audio Resampler Quality" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_QUALITY, + "Lower this value to favor performance/lower latency over audio quality, increase if you want better audio quality at the expense of performance/lower latency." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_WATCH_FOR_CHANGES, + "Watch shader files for changes" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, + "Auto-apply changes made to shader files on disk." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SHOW_DECORATIONS, + "Show Window Decorations" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STATISTICS_SHOW, + "Display Statistics" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STATISTICS_SHOW, + "Show onscreen technical statistics." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_ENABLE, + "Enable border filler" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, + "Enable border filler thickness" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, + "Enable background filler thickness" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, + "For 15 kHz CRT displays only. Attempts to use exact core/game resolution and refresh rate." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, + "CRT SwitchRes" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, + "When CRT SwitchRes is enabled, force ultrawide horizontal resolution to minimize mode switching." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, + "CRT Super Resolution" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, + "Show Rewind Settings" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, + "Show/hide the Rewind options." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_LATENCY, + "Show/hide the Latency options." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_LATENCY, + "Show Latency Settings" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_OVERLAYS, + "Show/hide the Overlay options." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_OVERLAYS, + "Show Overlay Settings" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE_MENU, + "Enable menu audio" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_ENABLE_MENU, + "Enable or disable menu sound." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_SETTINGS, + "Mixer Settings" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MIXER_SETTINGS, + "View and/or modify audio mixer settings." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_INFO, + "Info" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE, + "&File" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_LOAD_CORE, + "&Load Core..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_UNLOAD_CORE, + "&Unload Core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_EXIT, + "E&xit" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT, + "&Edit" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT_SEARCH, + "&Search" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW, + "&View" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_CLOSED_DOCKS, + "Closed Docks" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_SHADER_PARAMS, + "Shader Parameters" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS, + "&Options..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS, + "Remember dock positions:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY, + "Remember window geometry:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB, + "Remember last content browser tab:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME, + "Theme:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK, + "Dark" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM, + "Custom..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE, + "Options" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_TOOLS, + "&Tools" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP, + "&Help" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT, + "About RetroArch" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_DOCUMENTATION, + "Documentation" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOAD_CUSTOM_CORE, + "Load Custom Core..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOAD_CORE, + "Load Core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOADING_CORE, + "Loading Core..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_NAME, + "Name" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE_VERSION, + "Version" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_TAB_PLAYLISTS, + "Playlists" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER, + "File Browser" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_TOP, + "Top" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_UP, + "Up" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER, + "Content Browser" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_BOXART, + "Boxart" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_SCREENSHOT, + "Screenshot" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, + "Title Screen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, + "All Playlists" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE, + "Core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE_INFO, + "Core Info" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE_SELECTION_ASK, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_INFORMATION, + "Information" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_WARNING, + "Warning" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ERROR, + "Error" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR, + "Network Error" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESTART_TO_TAKE_EFFECT, + "Please restart the program for the changes to take effect." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOG, + "Log" + ) #ifdef HAVE_QT -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, - "Scan Finished.

    \n" - "In order for content to be correctly scanned, you must:\n" - "
    • have a compatible core already downloaded
    • \n" - "
    • have \"Core Info Files\" updated via Online Updater
    • \n" - "
    • have \"Databases\" updated via Online Updater
    • \n" - "
    • restart RetroArch if any of the above was just done
    \n" - "Finally, the content must match existing databases from here. If it is still not working, consider submitting a bug report.") MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHOW_WIMP, - "Show Desktop Menu" - ) + MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, + "Scan Finished.

    \n" + "In order for content to be correctly scanned, you must:\n" + "
    • have a compatible core already downloaded
    • \n" + "
    • have \"Core Info Files\" updated via Online Updater
    • \n" + "
    • have \"Databases\" updated via Online Updater
    • \n" + "
    • restart RetroArch if any of the above was just done
    \n" + "Finally, the content must match existing databases from here. If it is still not working, consider submitting a bug report." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_SHOW_WIMP, - "Opens the desktop menu if it was closed" - ) + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + "Show Desktop Menu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_WIMP, + "Opens the desktop menu if it was closed" + ) #endif -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, - "Don't show this again") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_STOP, - "Stop") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ASSOCIATE_CORE, - "Associate Core") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS, - "Hidden Playlists") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_HIDE, - "Hide") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR, - "Highlight color:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CHOOSE, - "&Choose...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SELECT_COLOR, - "Select Color") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SELECT_THEME, - "Select Theme") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CUSTOM_THEME, - "Custom Theme") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_PATH_IS_BLANK, - "File path is blank.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_IS_EMPTY, - "File is empty.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED, - "Could not open file for reading.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED, - "Could not open file for writing.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST, - "File does not exist.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST, - "Suggest loaded core first:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ZOOM, - "Zoom") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_VIEW, - "View") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_ICONS, - "Icons") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_LIST, - "List") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_OVERRIDE_OPTIONS, - "Overrides") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_OVERRIDE_OPTIONS, - "Options for overriding the global configuration.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY, - "Will start playback of the audio stream. Once finished, it will remove the current audio stream from memory.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_LOOPED, - "Will start playback of the audio stream. Once finished, it will loop and play the track again from the beginning.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_SEQUENTIAL, - "Will start playback of the audio stream. Once finished, it will jump to the next audio stream in sequential order and repeat this behavior. Useful as an album playback mode.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_STOP, - "This will stop playback of the audio stream, but not remove it from memory. You can start playing it again by selecting 'Play'.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_REMOVE, - "This will stop playback of the audio stream and remove it entirely from memory.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, - "Adjust the volume of the audio stream.") -MSG_HASH(MENU_ENUM_SUBLABEL_ADD_TO_MIXER, - "Add this audio track to an available audio stream slot. If no slots are currently available, it will be ignored.") -MSG_HASH(MENU_ENUM_SUBLABEL_ADD_TO_MIXER_AND_PLAY, - "Add this audio track to an available audio stream slot and play it. If no slots are currently available, it will be ignored.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY, - "Play") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_LOOPED, - "Play (Looped)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_SEQUENTIAL, - "Play (Sequential)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_STOP, - "Stop") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_REMOVE, - "Remove") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_VOLUME, - "Volume") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DETECT_CORE_LIST_OK_CURRENT_CORE, - "Current core") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, - "Clear") -MSG_HASH(MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE, - "Pause achievements for current session (This action will enable savestates, cheats, rewind, pause, and slow-motion).") -MSG_HASH(MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, - "Resume achievements for current session (This action will disable savestates, cheats, rewind, pause, and slow-motion and reset the current game).") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, - "In-Menu") MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, - "Enable Discord" - ) + MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, + "Don't show this again" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DISCORD_ALLOW, - "Enable or disable Discord support. Will not work with the browser version, only native desktop client." - ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIDI_INPUT, - "Input") -MSG_HASH(MENU_ENUM_SUBLABEL_MIDI_INPUT, - "Select input device.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIDI_OUTPUT, - "Output") -MSG_HASH(MENU_ENUM_SUBLABEL_MIDI_OUTPUT, - "Select output device.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIDI_VOLUME, - "Volume") -MSG_HASH(MENU_ENUM_SUBLABEL_MIDI_VOLUME, - "Set output volume (%).") -MSG_HASH(MENU_ENUM_LABEL_VALUE_POWER_MANAGEMENT_SETTINGS, - "Power Management") -MSG_HASH(MENU_ENUM_SUBLABEL_POWER_MANAGEMENT_SETTINGS, - "Change power management settings.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SUSTAINED_PERFORMANCE_MODE, - "Sustained Performance Mode") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_MPV_SUPPORT, - "mpv support") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_IDX, - "Index") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_MATCH_IDX, - "View Match #") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_MATCH, - "Match Address: %08X Mask: %02X") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_COPY_MATCH, - "Create Code Match #") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_MATCH, - "Delete Match #") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_BROWSE_MEMORY, - "Browse Address: %08X") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_DESC, - "Description") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_STATE, - "Enabled") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_CODE, - "Code") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_HANDLER, - "Handler") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_MEMORY_SEARCH_SIZE, - "Memory Search Size") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_TYPE, - "Type") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_VALUE, - "Value") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS, - "Memory Address") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS_BIT_POSITION, - "Memory Address Mask") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_TYPE, - "Rumble When Memory") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_VALUE, - "Rumble Value") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PORT, - "Rumble Port") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_STRENGTH, - "Rumble Primary Strength") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_DURATION, - "Rumble Primary Duration (ms)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_STRENGTH, - "Rumble Secondary Strength") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_DURATION, - "Rumble Secondary Duration (ms)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_AFTER, - "Add New Cheat After This One") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BEFORE, - "Add New Cheat Before This One") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_COPY_AFTER, - "Copy This Cheat After") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_COPY_BEFORE, - "Copy This Cheat Before") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_DELETE, - "Delete This Cheat") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_EMU, - "Emulator") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_RETRO, - "RetroArch") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_TYPE_DISABLED, - "") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_TYPE_SET_TO_VALUE, - "Set To Value") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_TYPE_INCREASE_VALUE, - "Increase By Value") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_TYPE_DECREASE_VALUE, - "Decrease By Value") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_EQ, - "Run next cheat if value = memory") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_NEQ, - "Run next cheat if value != memory") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_LT, - "Run next cheat if value < memory") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_GT, - "Run next cheat if value > memory") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_TYPE_DISABLED, - "") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_TYPE_CHANGES, - "Changes") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_TYPE_DOES_NOT_CHANGE, - "Does Not Change") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_TYPE_INCREASE, - "Increases") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_TYPE_DECREASE, - "Decreases") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_TYPE_EQ_VALUE, - "= Rumble Value") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_TYPE_NEQ_VALUE, - "!= Rumble Value") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_TYPE_LT_VALUE, - "< Rumble Value") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_TYPE_GT_VALUE, - "> Rumble Value") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_1, - "1-bit, max value = 0x01") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_2, - "2-bit, max value = 0x03") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_4, - "4-bit, max value = 0x0F") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_8, - "8-bit, max value = 0xFF") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_16, - "16-bit, max value = 0xFFFF") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_32, - "32-bit, max value = 0xFFFFFFFF") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_0, - "1") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_1, - "2") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_2, - "3") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_3, - "4") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_4, - "5") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_5, - "6") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_6, - "7") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_7, - "8") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_8, - "9") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_9, - "10") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_10, - "11") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_11, - "12") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_12, - "13") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_13, - "14") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_14, - "15") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_15, - "16") -MSG_HASH(MENU_ENUM_LABEL_RUMBLE_PORT_16, - "All") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_CONT, - "Start or Continue Cheat Search") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_RESTART, - "Start or Restart Cheat Search") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EXACT, - "Search Memory For Values") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LT, - "Search Memory For Values") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GT, - "Search Memory For Values") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQ, - "Search Memory For Values") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GTE, - "Search Memory For Values") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LTE, - "Search Memory For Values") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_NEQ, - "Search Memory For Values") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQPLUS, - "Search Memory For Values") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQMINUS, - "Search Memory For Values") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_ADD_MATCHES, - "Add the %u Matches to Your List") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, - "View the List of %u Matches") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_CREATE_OPTION, - "Create Code From This Match") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_OPTION, - "Delete This Match") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_TOP, - "Add New Code to Top") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BOTTOM, - "Add New Code to Bottom") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_ALL, - "Delete All Codes") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_RELOAD_CHEATS, - "Reload Game-Specific Cheats") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_SEARCH_EXACT_VAL, - "Equal to %u (%X)") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_SEARCH_LT_VAL, - "Less Than Before") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_SEARCH_GT_VAL, - "Greater Than Before") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_SEARCH_LTE_VAL, - "Less Than or Equal To Before") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_SEARCH_GTE_VAL, - "Greater Than or Equal To Before") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_SEARCH_EQ_VAL, - "Equal to Before") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_SEARCH_NEQ_VAL, - "Not Equal to Before") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_SEARCH_EQPLUS_VAL, - "Equal to Before+%u (%X)") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_SEARCH_EQMINUS_VAL, - "Equal to Before-%u (%X)") -MSG_HASH(MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS, - "Start or Continue Cheat Search") -MSG_HASH(MSG_CHEAT_INIT_SUCCESS, - "Successfully started cheat search") -MSG_HASH(MSG_CHEAT_INIT_FAIL, - "Failed to start cheat search") -MSG_HASH(MSG_CHEAT_SEARCH_NOT_INITIALIZED, - "Searching has not been initialized/started") -MSG_HASH(MSG_CHEAT_SEARCH_FOUND_MATCHES, - "New match count = %u") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_BIG_ENDIAN, - "Big Endian") -MSG_HASH(MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS, - "Added %u matches") -MSG_HASH(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL, - "Failed to add matches") -MSG_HASH(MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS, - "Created code from match") -MSG_HASH(MSG_CHEAT_SEARCH_ADD_MATCH_FAIL, - "Failed to create code") -MSG_HASH(MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS, - "Deleted match") -MSG_HASH(MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY, - "Not enough room. The total number of cheats you can have is 100.") -MSG_HASH(MSG_CHEAT_ADD_TOP_SUCCESS, - "New cheat added to top of list.") -MSG_HASH(MSG_CHEAT_ADD_BOTTOM_SUCCESS, - "New cheat added to bottom of list.") -MSG_HASH(MSG_CHEAT_DELETE_ALL_INSTRUCTIONS, - "Press right five times to delete all cheats.") -MSG_HASH(MSG_CHEAT_DELETE_ALL_SUCCESS, - "All cheats deleted.") -MSG_HASH(MSG_CHEAT_ADD_BEFORE_SUCCESS, - "New cheat added before this one.") -MSG_HASH(MSG_CHEAT_ADD_AFTER_SUCCESS, - "New cheat added after this one.") -MSG_HASH(MSG_CHEAT_COPY_BEFORE_SUCCESS, - "Cheat copied before this one.") -MSG_HASH(MSG_CHEAT_COPY_AFTER_SUCCESS, - "Cheat copied after this one.") -MSG_HASH(MSG_CHEAT_DELETE_SUCCESS, - "Cheat deleted.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PROGRESS, - "Progress:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT, - "\"All Playlists\" max list entries:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT, - "\"All Playlists\" max grid entries:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES, - "Show hidden files and folders:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST, - "New Playlist") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME, - "Please enter the new playlist name:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST, - "Delete Playlist") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, - "Are you sure you want to delete the playlist \"%1\"?") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_QUESTION, - "Question") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, - "Could not delete file.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE, - "Could not rename file.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, - "Gathering list of files...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, - "Adding files to playlist...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY, - "Playlist Entry") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_NAME, - "Name:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_PATH, - "Path:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE, - "Core:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, - "Database:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, - "(used to find thumbnails)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM, - "Are you sure you want to delete the item \"%1\"?") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS, - "Please choose a single playlist first.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DELETE, - "Delete") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ADD_ENTRY, - "Add Entry...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ADD_FILES, - "Add File(s)...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ADD_FOLDER, - "Add Folder...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_EDIT, - "Edit") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SELECT_FILES, - "Select Files") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SELECT_FOLDER, - "Select Folder") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY, - "Error updating playlist entry.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS, - "Please fill out all required fields.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY, - "Update RetroArch (nightly)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED, - "RetroArch updated successfully. Please restart the application for the changes to take effect.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, - "Update failed.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT_CONTRIBUTORS, - "Contributors") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, - "Current shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, - "Move Down") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, - "Move Up") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOAD, - "Load") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SAVE, - "Save") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_REMOVE, - "Remove") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_APPLY, - "Apply") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, - "Add Pass") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, - "Clear All Passes") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, - "No shader passes.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_PASS, - "Reset Pass") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, - "Reset All Passes") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, - "Reset Parameter") + MENU_ENUM_LABEL_VALUE_QT_STOP, + "Stop" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ASSOCIATE_CORE, + "Associate Core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS, + "Hidden Playlists" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_HIDE, + "Hide" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR, + "Highlight color:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CHOOSE, + "&Choose..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SELECT_COLOR, + "Select Color" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SELECT_THEME, + "Select Theme" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CUSTOM_THEME, + "Custom Theme" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_PATH_IS_BLANK, + "File path is blank." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_IS_EMPTY, + "File is empty." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED, + "Could not open file for reading." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED, + "Could not open file for writing." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST, + "File does not exist." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST, + "Suggest loaded core first:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ZOOM, + "Zoom" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_VIEW, + "View" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_ICONS, + "Icons" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_LIST, + "List" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_OVERRIDE_OPTIONS, + "Overrides" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_OVERRIDE_OPTIONS, + "Options for overriding the global configuration." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY, + "Will start playback of the audio stream. Once finished, it will remove the current audio stream from memory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_LOOPED, + "Will start playback of the audio stream. Once finished, it will loop and play the track again from the beginning." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_SEQUENTIAL, + "Will start playback of the audio stream. Once finished, it will jump to the next audio stream in sequential order and repeat this behavior. Useful as an album playback mode." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_STOP, + "This will stop playback of the audio stream, but not remove it from memory. You can start playing it again by selecting 'Play'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_REMOVE, + "This will stop playback of the audio stream and remove it entirely from memory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, + "Adjust the volume of the audio stream." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_MIXER, + "Add this audio track to an available audio stream slot. If no slots are currently available, it will be ignored." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_MIXER_AND_PLAY, + "Add this audio track to an available audio stream slot and play it. If no slots are currently available, it will be ignored." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY, + "Play" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_LOOPED, + "Play (Looped)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_SEQUENTIAL, + "Play (Sequential)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_STOP, + "Stop" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_REMOVE, + "Remove" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_VOLUME, + "Volume" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DETECT_CORE_LIST_OK_CURRENT_CORE, + "Current core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, + "Clear" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE, + "Pause achievements for current session (This action will enable savestates, cheats, rewind, pause, and slow-motion)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, + "Resume achievements for current session (This action will disable savestates, cheats, rewind, pause, and slow-motion and reset the current game)." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, + "In-Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, + "Enable Discord" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISCORD_ALLOW, + "Enable or disable Discord support. Will not work with the browser version, only native desktop client." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIDI_INPUT, + "Input" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIDI_INPUT, + "Select input device." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIDI_OUTPUT, + "Output" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIDI_OUTPUT, + "Select output device." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIDI_VOLUME, + "Volume" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIDI_VOLUME, + "Set output volume (%)." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_POWER_MANAGEMENT_SETTINGS, + "Power Management" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_POWER_MANAGEMENT_SETTINGS, + "Change power management settings." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SUSTAINED_PERFORMANCE_MODE, + "Sustained Performance Mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_MPV_SUPPORT, + "mpv support" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_IDX, + "Index" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_MATCH_IDX, + "View Match #" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_MATCH, + "Match Address: %08X Mask: %02X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_MATCH, + "Create Code Match #" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_MATCH, + "Delete Match #" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_BROWSE_MEMORY, + "Browse Address: %08X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DESC, + "Description" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_STATE, + "Enabled" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_CODE, + "Code" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_HANDLER, + "Handler" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_MEMORY_SEARCH_SIZE, + "Memory Search Size" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_TYPE, + "Type" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_VALUE, + "Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS, + "Memory Address" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS_BIT_POSITION, + "Memory Address Mask" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_TYPE, + "Rumble When Memory" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_VALUE, + "Rumble Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PORT, + "Rumble Port" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_STRENGTH, + "Rumble Primary Strength" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_DURATION, + "Rumble Primary Duration (ms)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_STRENGTH, + "Rumble Secondary Strength" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_DURATION, + "Rumble Secondary Duration (ms)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_AFTER, + "Add New Cheat After This One" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BEFORE, + "Add New Cheat Before This One" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_AFTER, + "Copy This Cheat After" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_BEFORE, + "Copy This Cheat Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE, + "Delete This Cheat" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_EMU, + "Emulator" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_RETRO, + "RetroArch" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_DISABLED, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_SET_TO_VALUE, + "Set To Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_INCREASE_VALUE, + "Increase By Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_DECREASE_VALUE, + "Decrease By Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_EQ, + "Run next cheat if value = memory" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_NEQ, + "Run next cheat if value != memory" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_LT, + "Run next cheat if value < memory" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_GT, + "Run next cheat if value > memory" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_DISABLED, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_CHANGES, + "Changes" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_DOES_NOT_CHANGE, + "Does Not Change" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_INCREASE, + "Increases" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_DECREASE, + "Decreases" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_EQ_VALUE, + "= Rumble Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_NEQ_VALUE, + "!= Rumble Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_LT_VALUE, + "< Rumble Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_GT_VALUE, + "> Rumble Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_1, + "1-bit, max value = 0x01" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_2, + "2-bit, max value = 0x03" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_4, + "4-bit, max value = 0x0F" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_8, + "8-bit, max value = 0xFF" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_16, + "16-bit, max value = 0xFFFF" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_32, + "32-bit, max value = 0xFFFFFFFF" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_0, + "1" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_1, + "2" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_2, + "3" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_3, + "4" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_4, + "5" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_5, + "6" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_6, + "7" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_7, + "8" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_8, + "9" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_9, + "10" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_10, + "11" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_11, + "12" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_12, + "13" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_13, + "14" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_14, + "15" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_15, + "16" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_16, + "All" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_CONT, + "Start or Continue Cheat Search" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_RESTART, + "Start or Restart Cheat Search" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EXACT, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LT, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GT, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQ, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GTE, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LTE, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_NEQ, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQPLUS, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQMINUS, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_MATCHES, + "Add the %u Matches to Your List" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, + "View the List of %u Matches" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_CREATE_OPTION, + "Create Code From This Match" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_OPTION, + "Delete This Match" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_TOP, + "Add New Code to Top" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BOTTOM, + "Add New Code to Bottom" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_ALL, + "Delete All Codes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RELOAD_CHEATS, + "Reload Game-Specific Cheats" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EXACT_VAL, + "Equal to %u (%X)" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_LT_VAL, + "Less Than Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_GT_VAL, + "Greater Than Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_LTE_VAL, + "Less Than or Equal To Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_GTE_VAL, + "Greater Than or Equal To Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EQ_VAL, + "Equal to Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_NEQ_VAL, + "Not Equal to Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EQPLUS_VAL, + "Equal to Before+%u (%X)" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EQMINUS_VAL, + "Equal to Before-%u (%X)" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS, + "Start or Continue Cheat Search" + ) +MSG_HASH( + MSG_CHEAT_INIT_SUCCESS, + "Successfully started cheat search" + ) +MSG_HASH( + MSG_CHEAT_INIT_FAIL, + "Failed to start cheat search" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_NOT_INITIALIZED, + "Searching has not been initialized/started" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_FOUND_MATCHES, + "New match count = %u" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_BIG_ENDIAN, + "Big Endian" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS, + "Added %u matches" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL, + "Failed to add matches" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS, + "Created code from match" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_FAIL, + "Failed to create code" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS, + "Deleted match" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY, + "Not enough room. The total number of cheats you can have is 100." + ) +MSG_HASH( + MSG_CHEAT_ADD_TOP_SUCCESS, + "New cheat added to top of list." + ) +MSG_HASH( + MSG_CHEAT_ADD_BOTTOM_SUCCESS, + "New cheat added to bottom of list." + ) +MSG_HASH( + MSG_CHEAT_DELETE_ALL_INSTRUCTIONS, + "Press right five times to delete all cheats." + ) +MSG_HASH( + MSG_CHEAT_DELETE_ALL_SUCCESS, + "All cheats deleted." + ) +MSG_HASH( + MSG_CHEAT_ADD_BEFORE_SUCCESS, + "New cheat added before this one." + ) +MSG_HASH( + MSG_CHEAT_ADD_AFTER_SUCCESS, + "New cheat added after this one." + ) +MSG_HASH( + MSG_CHEAT_COPY_BEFORE_SUCCESS, + "Cheat copied before this one." + ) +MSG_HASH( + MSG_CHEAT_COPY_AFTER_SUCCESS, + "Cheat copied after this one." + ) +MSG_HASH( + MSG_CHEAT_DELETE_SUCCESS, + "Cheat deleted." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PROGRESS, + "Progress:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT, + "\"All Playlists\" max list entries:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT, + "\"All Playlists\" max grid entries:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES, + "Show hidden files and folders:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST, + "New Playlist" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME, + "Please enter the new playlist name:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST, + "Delete Playlist" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, + "Are you sure you want to delete the playlist \"%1\"?" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_QUESTION, + "Question" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, + "Could not delete file." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE, + "Could not rename file." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, + "Gathering list of files..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, + "Adding files to playlist..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY, + "Playlist Entry" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_NAME, + "Name:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_PATH, + "Path:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE, + "Core:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, + "Database:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, + "(used to find thumbnails)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM, + "Are you sure you want to delete the item \"%1\"?" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS, + "Please choose a single playlist first." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DELETE, + "Delete" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_ENTRY, + "Add Entry..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_FILES, + "Add File(s)..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_FOLDER, + "Add Folder..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_EDIT, + "Edit" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SELECT_FILES, + "Select Files" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SELECT_FOLDER, + "Select Folder" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY, + "Error updating playlist entry." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS, + "Please fill out all required fields." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY, + "Update RetroArch (nightly)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED, + "RetroArch updated successfully. Please restart the application for the changes to take effect." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, + "Update failed." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT_CONTRIBUTORS, + "Contributors" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, + "Current shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, + "Move Down" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, + "Move Up" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOAD, + "Load" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SAVE, + "Save" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_REMOVE, + "Remove" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_APPLY, + "Apply" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, + "Add Pass" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, + "Clear All Passes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, + "No shader passes." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_PASS, + "Reset Pass" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, + "Reset All Passes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, + "Reset Parameter" + ) \ No newline at end of file From 96023ea469982f1c6dc493a5a70e91d261486c40 Mon Sep 17 00:00:00 2001 From: TheMrIron2 Date: Tue, 21 Aug 2018 20:48:55 +0000 Subject: [PATCH 124/182] PSP: Slightly more aggressive optimisation - O3 flag replacing O2 for higher level of optimisation. Potentially unstable, but works for Wii U RetroArch along with other PSP emulators. I don't see why not. - fsingle-precision-constant to simplify some operations. Should be safe while being more performant due to using less memory traffic and may lessen load on the CPU because of the simplification. --- Makefile.psp1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.psp1 b/Makefile.psp1 index cf57142100..be0ae8e25a 100644 --- a/Makefile.psp1 +++ b/Makefile.psp1 @@ -13,7 +13,7 @@ TARGET = retroarchpsp ifeq ($(DEBUG), 1) OPTIMIZE_LV := -O0 -g else - OPTIMIZE_LV := -O2 + OPTIMIZE_LV := -O3 endif ifeq ($(WHOLE_ARCHIVE_LINK), 1) @@ -22,7 +22,7 @@ ifeq ($(WHOLE_ARCHIVE_LINK), 1) endif INCDIR = deps deps/stb deps/libz deps/7zip deps/pthreads deps/pthreads/platform/psp deps/pthreads/platform/helper libretro-common/include -CFLAGS = $(OPTIMIZE_LV) -G0 -std=gnu99 -ffast-math +CFLAGS = $(OPTIMIZE_LV) -G0 -std=gnu99 -ffast-math -fsingle-precision-constant ASFLAGS = $(CFLAGS) RARCH_DEFINES = -DPSP -D_MIPS_ARCH_ALLEGREX -DHAVE_LANGEXTRA -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DWANT_ZLIB -DHAVE_GRIFFIN=1 -DRARCH_INTERNAL -DRARCH_CONSOLE -DHAVE_MENU -DHAVE_RGUI -DHAVE_FILTERS_BUILTIN -DHAVE_7ZIP -DHAVE_CC_RESAMPLER From 498ed160bb29ace566493743a551808f91a2930f Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 21 Aug 2018 18:25:20 -0400 Subject: [PATCH 125/182] Qt: fix shader passes disappearing on context reset --- ui/drivers/qt/shaderparamsdialog.cpp | 75 ++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index b7ed0a2cd0..e078ff7b44 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -66,6 +66,8 @@ void ShaderParamsDialog::resizeEvent(QResizeEvent *event) return; m_scrollArea->resize(event->size()); + + emit resized(event->size()); } void ShaderParamsDialog::closeEvent(QCloseEvent *event) @@ -475,7 +477,7 @@ void ShaderParamsDialog::onShaderResetPass(int pass) } } - emit reload(); + reload(); } void ShaderParamsDialog::onShaderResetParameter(int parameter) @@ -510,12 +512,12 @@ void ShaderParamsDialog::onShaderResetParameter(int parameter) param->current = param->initial; } - emit reload(); + reload(); } void ShaderParamsDialog::onShaderResetAllPasses() { - emit onShaderResetPass(-1); + onShaderResetPass(-1); } void ShaderParamsDialog::onShaderAddPassClicked() @@ -700,7 +702,7 @@ void ShaderParamsDialog::onShaderClearAllPassesClicked() while (menu_shader->passes > 0) menu_shader_manager_decrement_amount_passes(); - emit onShaderApplyClicked(); + onShaderApplyClicked(); #endif } @@ -741,7 +743,7 @@ void ShaderParamsDialog::onShaderRemovePassClicked() menu_shader_manager_decrement_amount_passes(); - emit onShaderApplyClicked(); + onShaderApplyClicked(); #endif } @@ -752,7 +754,7 @@ void ShaderParamsDialog::onShaderApplyClicked() void ShaderParamsDialog::reload() { - emit buildLayout(); + buildLayout(); } void ShaderParamsDialog::buildLayout() @@ -767,6 +769,7 @@ void ShaderParamsDialog::buildLayout() QMenu *removeMenu = NULL; struct video_shader *menu_shader = NULL; struct video_shader *video_shader = NULL; + struct video_shader *avail_shader = NULL; const char *shader_path = NULL; int i; unsigned j; @@ -777,20 +780,50 @@ void ShaderParamsDialog::buildLayout() /* NOTE: For some reason, menu_shader_get() returns a COPY of what get_current_shader() gives us. * And if you want to be able to change shader settings/parameters from both the raster menu and * Qt at the same time... you must change BOTH or one will overwrite the other. + * + * AND, during a context reset, video_shader will be NULL but not menu_shader, so don't totally bail + * just because video_shader is NULL. + * + * Someone please fix this mess. */ - if ((video_shader && video_shader->passes == 0) || !video_shader) + if (video_shader) + { + avail_shader = video_shader; + + if (video_shader->passes == 0) + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); + } + else if (menu_shader) + { + avail_shader = menu_shader; + + if (menu_shader->passes == 0) + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); + } + else setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); - emit clearLayout(); + clearLayout(); /* Only check video_shader for the path, menu_shader seems stale... e.g. if you remove all the shader passes, * it still has the old path in it, but video_shader does not */ - if (video_shader && !string_is_empty(video_shader->path)) + if (video_shader) { - shader_path = video_shader->path; - setWindowTitle(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER)) + ": " + QFileInfo(shader_path).fileName()); + if (!string_is_empty(video_shader->path)) + { + shader_path = video_shader->path; + setWindowTitle(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER)) + ": " + QFileInfo(shader_path).fileName()); + } + } + else if (menu_shader) + { + if (!string_is_empty(menu_shader->path)) + { + shader_path = menu_shader->path; + setWindowTitle(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER)) + ": " + QFileInfo(shader_path).fileName()); + } } else setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); @@ -846,11 +879,11 @@ void ShaderParamsDialog::buildLayout() m_layout->addLayout(topButtonLayout); /* NOTE: We assume that parameters are always grouped in order by the pass number, e.g., all parameters for pass 0 come first, then params for pass 1, etc. */ - for (i = 0; video_shader && i < static_cast(video_shader->passes); i++) + for (i = 0; avail_shader && i < static_cast(avail_shader->passes); i++) { QFormLayout *form = NULL; QGroupBox *groupBox = NULL; - QFileInfo fileInfo(video_shader->pass[i].source.path); + QFileInfo fileInfo(avail_shader->pass[i].source.path); QString shaderBasename = fileInfo.completeBaseName(); QHBoxLayout *filterScaleHBoxLayout = NULL; QComboBox *filterComboBox = new QComboBox(this); @@ -877,7 +910,7 @@ void ShaderParamsDialog::buildLayout() moveUpButton->setProperty("pass", i); /* Can't move down if we're already at the bottom. */ - if (i < static_cast(video_shader->passes) - 1) + if (i < static_cast(avail_shader->passes) - 1) connect(moveDownButton, SIGNAL(clicked()), this, SLOT(onShaderPassMoveDownClicked())); else moveDownButton->setDisabled(true); @@ -915,8 +948,8 @@ void ShaderParamsDialog::buildLayout() scaleComboBox->addItem(label, j); } - filterComboBox->setCurrentIndex(static_cast(video_shader->pass[i].filter)); - scaleComboBox->setCurrentIndex(static_cast(video_shader->pass[i].fbo.scale_x)); + filterComboBox->setCurrentIndex(static_cast(avail_shader->pass[i].filter)); + scaleComboBox->setCurrentIndex(static_cast(avail_shader->pass[i].fbo.scale_x)); /* connect the signals only after the initial index is set */ connect(filterComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onFilterComboBoxIndexChanged(int))); @@ -948,9 +981,9 @@ void ShaderParamsDialog::buildLayout() form->addRow("", filterScaleHBoxLayout); - for (j = 0; j < video_shader->num_parameters; j++) + for (j = 0; j < avail_shader->num_parameters; j++) { - struct video_shader_parameter *param = &video_shader->parameters[j]; + struct video_shader_parameter *param = &avail_shader->parameters[j]; if (param->pass != i) continue; @@ -1011,7 +1044,7 @@ void ShaderParamsDialog::onParameterLabelContextMenuRequested(const QPoint&) if (action == resetParamAction.data()) { - emit onShaderResetParameter(parameter); + onShaderResetParameter(parameter); } } @@ -1054,11 +1087,11 @@ void ShaderParamsDialog::onGroupBoxContextMenuRequested(const QPoint&) if (action == resetPassAction.data()) { - emit onShaderResetPass(pass); + onShaderResetPass(pass); } else if (action == resetAllPassesAction.data()) { - emit onShaderResetAllPasses(); + onShaderResetAllPasses(); } } From 0b9adb39386cf192268a119d64a691af0374e739 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 21 Aug 2018 19:16:18 -0400 Subject: [PATCH 126/182] Qt: fix pass parameters switched around on context reset if move up/down buttons were used --- ui/drivers/qt/shaderparamsdialog.cpp | 64 ++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index e078ff7b44..63ea2be49f 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -323,18 +323,50 @@ void ShaderParamsDialog::onShaderPassMoveDownClicked() if (video_shader) { + int i; + if (pass >= static_cast(video_shader->passes) - 1) return; std::swap(video_shader->pass[pass], video_shader->pass[pass + 1]); + + for (i = 0; i < static_cast(video_shader->num_parameters); i++) + { + struct video_shader_parameter *param = &video_shader->parameters[i]; + + if (param->pass == pass) + { + param->pass += 1; + } + else if (param->pass == pass + 1) + { + param->pass -= 1; + } + } } if (menu_shader) { + int i; + if (pass >= static_cast(menu_shader->passes) - 1) return; std::swap(menu_shader->pass[pass], menu_shader->pass[pass + 1]); + + for (i = 0; i < static_cast(menu_shader->num_parameters); i++) + { + struct video_shader_parameter *param = &menu_shader->parameters[i]; + + if (param->pass == pass) + { + param->pass += 1; + } + else if (param->pass == pass + 1) + { + param->pass -= 1; + } + } } command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); @@ -369,18 +401,50 @@ void ShaderParamsDialog::onShaderPassMoveUpClicked() if (video_shader) { + int i; + if (pass > static_cast(video_shader->passes) - 1) return; std::swap(video_shader->pass[pass - 1], video_shader->pass[pass]); + + for (i = 0; i < static_cast(video_shader->num_parameters); i++) + { + struct video_shader_parameter *param = &video_shader->parameters[i]; + + if (param->pass == pass) + { + param->pass -= 1; + } + else if (param->pass == pass - 1) + { + param->pass += 1; + } + } } if (menu_shader) { + int i; + if (pass > static_cast(menu_shader->passes) - 1) return; std::swap(menu_shader->pass[pass - 1], menu_shader->pass[pass]); + + for (i = 0; i < static_cast(menu_shader->num_parameters); i++) + { + struct video_shader_parameter *param = &menu_shader->parameters[i]; + + if (param->pass == pass) + { + param->pass -= 1; + } + else if (param->pass == pass - 1) + { + param->pass += 1; + } + } } command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); From 67653ba5f07e6efe06c5eb098a7bab1eeeb4f361 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 21 Aug 2018 21:01:56 -0400 Subject: [PATCH 127/182] Qt: try to fix wrong parameter being set in a different way --- ui/drivers/qt/shaderparamsdialog.cpp | 77 +++------------------------- 1 file changed, 6 insertions(+), 71 deletions(-) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 63ea2be49f..38d6d0a31d 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -323,50 +323,18 @@ void ShaderParamsDialog::onShaderPassMoveDownClicked() if (video_shader) { - int i; - if (pass >= static_cast(video_shader->passes) - 1) return; std::swap(video_shader->pass[pass], video_shader->pass[pass + 1]); - - for (i = 0; i < static_cast(video_shader->num_parameters); i++) - { - struct video_shader_parameter *param = &video_shader->parameters[i]; - - if (param->pass == pass) - { - param->pass += 1; - } - else if (param->pass == pass + 1) - { - param->pass -= 1; - } - } } if (menu_shader) { - int i; - if (pass >= static_cast(menu_shader->passes) - 1) return; std::swap(menu_shader->pass[pass], menu_shader->pass[pass + 1]); - - for (i = 0; i < static_cast(menu_shader->num_parameters); i++) - { - struct video_shader_parameter *param = &menu_shader->parameters[i]; - - if (param->pass == pass) - { - param->pass += 1; - } - else if (param->pass == pass + 1) - { - param->pass -= 1; - } - } } command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); @@ -401,50 +369,18 @@ void ShaderParamsDialog::onShaderPassMoveUpClicked() if (video_shader) { - int i; - if (pass > static_cast(video_shader->passes) - 1) return; std::swap(video_shader->pass[pass - 1], video_shader->pass[pass]); - - for (i = 0; i < static_cast(video_shader->num_parameters); i++) - { - struct video_shader_parameter *param = &video_shader->parameters[i]; - - if (param->pass == pass) - { - param->pass -= 1; - } - else if (param->pass == pass - 1) - { - param->pass += 1; - } - } } if (menu_shader) { - int i; - if (pass > static_cast(menu_shader->passes) - 1) return; std::swap(menu_shader->pass[pass - 1], menu_shader->pass[pass]); - - for (i = 0; i < static_cast(menu_shader->num_parameters); i++) - { - struct video_shader_parameter *param = &menu_shader->parameters[i]; - - if (param->pass == pass) - { - param->pass -= 1; - } - else if (param->pass == pass - 1) - { - param->pass += 1; - } - } } command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); @@ -858,16 +794,15 @@ void ShaderParamsDialog::buildLayout() if (video_shader->passes == 0) setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); } - else if (menu_shader) - { - avail_shader = menu_shader; - - if (menu_shader->passes == 0) - setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); - } else + { setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); + /* video_shader isn't available yet, just keep retrying until it is */ + QTimer::singleShot(0, this, SLOT(buildLayout())); + return; + } + clearLayout(); /* Only check video_shader for the path, menu_shader seems stale... e.g. if you remove all the shader passes, From 8ff257290c10163b8dd44c537eb5a83a89b57741 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 21 Aug 2018 21:20:25 -0400 Subject: [PATCH 128/182] Qt: hopefully parameters are fixed now --- ui/drivers/qt/shaderparamsdialog.cpp | 64 ++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 38d6d0a31d..7c84106f3e 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -323,17 +323,49 @@ void ShaderParamsDialog::onShaderPassMoveDownClicked() if (video_shader) { + int i; + if (pass >= static_cast(video_shader->passes) - 1) return; + for (i = 0; i < static_cast(video_shader->num_parameters); i++) + { + struct video_shader_parameter *param = &video_shader->parameters[i]; + + if (param->pass == pass) + { + param->pass += 1; + } + else if (param->pass == pass + 1) + { + param->pass -= 1; + } + } + std::swap(video_shader->pass[pass], video_shader->pass[pass + 1]); } if (menu_shader) { + int i; + if (pass >= static_cast(menu_shader->passes) - 1) return; + for (i = 0; i < static_cast(menu_shader->num_parameters); i++) + { + struct video_shader_parameter *param = &menu_shader->parameters[i]; + + if (param->pass == pass) + { + param->pass += 1; + } + else if (param->pass == pass + 1) + { + param->pass -= 1; + } + } + std::swap(menu_shader->pass[pass], menu_shader->pass[pass + 1]); } @@ -369,18 +401,50 @@ void ShaderParamsDialog::onShaderPassMoveUpClicked() if (video_shader) { + int i; + if (pass > static_cast(video_shader->passes) - 1) return; std::swap(video_shader->pass[pass - 1], video_shader->pass[pass]); + + for (i = 0; i < static_cast(video_shader->num_parameters); i++) + { + struct video_shader_parameter *param = &video_shader->parameters[i]; + + if (param->pass == pass) + { + param->pass -= 1; + } + else if (param->pass == pass - 1) + { + param->pass += 1; + } + } } if (menu_shader) { + int i; + if (pass > static_cast(menu_shader->passes) - 1) return; std::swap(menu_shader->pass[pass - 1], menu_shader->pass[pass]); + + for (i = 0; i < static_cast(menu_shader->num_parameters); i++) + { + struct video_shader_parameter *param = &menu_shader->parameters[i]; + + if (param->pass == pass) + { + param->pass -= 1; + } + else if (param->pass == pass - 1) + { + param->pass += 1; + } + } } command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); From b118e45d49c7f795f828f74d4b4ab540264ebb9b Mon Sep 17 00:00:00 2001 From: Alfrix Date: Wed, 22 Aug 2018 12:51:59 -0300 Subject: [PATCH 129/182] Don't show the pipeline option it was disabled in the build --- menu/menu_setting.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 40f65a60a2..a83667cd68 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -6391,6 +6391,7 @@ static bool setting_append_list( general_read_handler, SD_FLAG_NONE); +#ifdef HAVE_SHADERPIPELINE if (video_shader_any_supported()) { CONFIG_UINT( @@ -6406,6 +6407,7 @@ static bool setting_append_list( general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, XMB_SHADER_PIPELINE_LAST-1, 1, true, true); } +#endif CONFIG_UINT( list, list_info, From 947113d0074818edcdc53c43c6c0911d9a88accf Mon Sep 17 00:00:00 2001 From: Alfrix Date: Wed, 22 Aug 2018 16:31:02 -0300 Subject: [PATCH 130/182] Change start core icon --- menu/drivers/xmb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 9260bc1c56..041613520d 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2289,6 +2289,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_CONTENT_SETTINGS: case MENU_ENUM_LABEL_UPDATE_ASSETS: return xmb->textures.list[XMB_TEXTURE_QUICKMENU]; + case MENU_ENUM_LABEL_START_CORE: + return xmb->textures.list[XMB_TEXTURE_RUN]; case MENU_ENUM_LABEL_CORE_LIST: case MENU_ENUM_LABEL_CORE_SETTINGS: case MENU_ENUM_LABEL_CORE_UPDATER_LIST: From fb15edebc38546fda0fa249390e4569bab33b208 Mon Sep 17 00:00:00 2001 From: Alfrix Date: Wed, 22 Aug 2018 19:52:27 -0300 Subject: [PATCH 131/182] Add Retrosystem to the support list of menu icons --- menu/drivers/xmb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 041613520d..b3a8349f97 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2280,7 +2280,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, if (settings->uints.menu_xmb_theme == XMB_ICON_THEME_MONOCHROME || settings->uints.menu_xmb_theme == XMB_ICON_THEME_MONOCHROME_INVERTED || settings->uints.menu_xmb_theme == XMB_ICON_THEME_CUSTOM || - settings->uints.menu_xmb_theme == XMB_ICON_THEME_DOTART + settings->uints.menu_xmb_theme == XMB_ICON_THEME_DOTART || + settings->uints.menu_xmb_theme == XMB_ICON_THEME_RETROSYSTEM ) { switch (enum_idx) From 88cecc521a573e0ccef13719f94d1ade97e82848 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 22 Aug 2018 22:51:44 -0400 Subject: [PATCH 132/182] Qt: hopefully parameters are fixed now part 2 --- menu/menu_shader.c | 2 +- ui/drivers/qt/shaderparamsdialog.cpp | 59 ++++++++++++++++++++++++---- ui/drivers/qt/shaderparamsdialog.h | 13 ++++++ 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/menu/menu_shader.c b/menu/menu_shader.c index f6855c82fa..379be3709e 100644 --- a/menu/menu_shader.c +++ b/menu/menu_shader.c @@ -303,7 +303,7 @@ bool menu_shader_manager_save_preset( { strlcpy(default_preset, "menu", sizeof(default_preset)); - strlcat(default_preset, + strlcat(default_preset, preset_ext, sizeof(default_preset)); } diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 7c84106f3e..eceb0fa1a8 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -41,6 +41,33 @@ enum SHADER_PRESET_SAVE_NORMAL }; +ShaderPass::ShaderPass(struct video_shader_pass *passToCopy) : + pass(NULL) +{ + if (passToCopy) + { + pass = (struct video_shader_pass*)calloc(1, sizeof(*pass)); + memcpy(pass, passToCopy, sizeof(*pass)); + } +} + +ShaderPass::~ShaderPass() +{ + if (pass) + free(pass); +} + +ShaderPass& ShaderPass::operator=(const ShaderPass &other) +{ + if (this != &other && other.pass) + { + pass = (struct video_shader_pass*)calloc(1, sizeof(*pass)); + memcpy(pass, other.pass, sizeof(*pass)); + } + + return *this; +} + ShaderParamsDialog::ShaderParamsDialog(QWidget *parent) : QDialog(parent) ,m_layout() @@ -323,6 +350,7 @@ void ShaderParamsDialog::onShaderPassMoveDownClicked() if (video_shader) { + ShaderPass tempPass; int i; if (pass >= static_cast(video_shader->passes) - 1) @@ -342,11 +370,14 @@ void ShaderParamsDialog::onShaderPassMoveDownClicked() } } - std::swap(video_shader->pass[pass], video_shader->pass[pass + 1]); + tempPass = ShaderPass(&video_shader->pass[pass]); + memcpy(&video_shader->pass[pass], &video_shader->pass[pass + 1], sizeof(struct video_shader_pass)); + memcpy(&video_shader->pass[pass + 1], tempPass.pass, sizeof(struct video_shader_pass)); } if (menu_shader) { + ShaderPass tempPass; int i; if (pass >= static_cast(menu_shader->passes) - 1) @@ -366,10 +397,12 @@ void ShaderParamsDialog::onShaderPassMoveDownClicked() } } - std::swap(menu_shader->pass[pass], menu_shader->pass[pass + 1]); + tempPass = ShaderPass(&menu_shader->pass[pass]); + memcpy(&menu_shader->pass[pass], &menu_shader->pass[pass + 1], sizeof(struct video_shader_pass)); + memcpy(&menu_shader->pass[pass + 1], tempPass.pass, sizeof(struct video_shader_pass)); } - command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); + reload(); } void ShaderParamsDialog::onShaderPassMoveUpClicked() @@ -401,13 +434,12 @@ void ShaderParamsDialog::onShaderPassMoveUpClicked() if (video_shader) { + ShaderPass tempPass; int i; if (pass > static_cast(video_shader->passes) - 1) return; - std::swap(video_shader->pass[pass - 1], video_shader->pass[pass]); - for (i = 0; i < static_cast(video_shader->num_parameters); i++) { struct video_shader_parameter *param = &video_shader->parameters[i]; @@ -421,17 +453,20 @@ void ShaderParamsDialog::onShaderPassMoveUpClicked() param->pass += 1; } } + + tempPass = ShaderPass(&video_shader->pass[pass - 1]); + memcpy(&video_shader->pass[pass - 1], &video_shader->pass[pass], sizeof(struct video_shader_pass)); + memcpy(&video_shader->pass[pass], tempPass.pass, sizeof(struct video_shader_pass)); } if (menu_shader) { + ShaderPass tempPass; int i; if (pass > static_cast(menu_shader->passes) - 1) return; - std::swap(menu_shader->pass[pass - 1], menu_shader->pass[pass]); - for (i = 0; i < static_cast(menu_shader->num_parameters); i++) { struct video_shader_parameter *param = &menu_shader->parameters[i]; @@ -445,9 +480,13 @@ void ShaderParamsDialog::onShaderPassMoveUpClicked() param->pass += 1; } } + + tempPass = ShaderPass(&menu_shader->pass[pass - 1]); + memcpy(&menu_shader->pass[pass - 1], &menu_shader->pass[pass], sizeof(struct video_shader_pass)); + memcpy(&menu_shader->pass[pass], tempPass.pass, sizeof(struct video_shader_pass)); } - command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); + reload(); } void ShaderParamsDialog::onShaderLoadPresetClicked() @@ -1197,6 +1236,10 @@ void ShaderParamsDialog::addShaderParam(struct video_shader_parameter *param, in slider->setValue(value); slider->setProperty("param", parameter); + struct video_shader *video_shader = NULL; + + getShaders(NULL, &video_shader); + connect(slider, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSliderValueChanged(int))); box->addWidget(slider); diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h index 309e785234..4a0732180c 100644 --- a/ui/drivers/qt/shaderparamsdialog.h +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -4,6 +4,10 @@ #include #include +extern "C" { +#include "../.././gfx/video_shader_parse.h" +} + class QCloseEvent; class QResizeEvent; class QVBoxLayout; @@ -11,6 +15,15 @@ class QFormLayout; class QLayout; class QScrollArea; +class ShaderPass +{ +public: + ShaderPass(struct video_shader_pass *passToCopy = NULL); + ~ShaderPass(); + ShaderPass& operator=(const ShaderPass &other); + struct video_shader_pass *pass; +}; + class ShaderParamsDialog : public QDialog { Q_OBJECT From 27147226a0a3ca80cfa9675ac763b00d0715c538 Mon Sep 17 00:00:00 2001 From: Yarsan Hoessain <32988993+hyarsan@users.noreply.github.com> Date: Thu, 23 Aug 2018 15:27:09 +0200 Subject: [PATCH 133/182] Make the Show Desktop Menu sublabel sound better --- intl/msg_hash_us.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index ed7adac8e0..ab19bb328c 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -6487,7 +6487,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SHOW_WIMP, - "Opens the desktop menu if it was closed" + "Opens the desktop menu if closed." ) #endif MSG_HASH( From 6464003d5f649e2c13021d2663c8cefab0e57726 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 23 Aug 2018 11:42:21 -0400 Subject: [PATCH 134/182] Qt: use id instead of array index for shader params, fix empty window on vulkan --- ui/drivers/qt/shaderparamsdialog.cpp | 181 ++++++++++++++++++++------- ui/drivers/qt/shaderparamsdialog.h | 4 +- 2 files changed, 138 insertions(+), 47 deletions(-) diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index eceb0fa1a8..2ed8ecdaf4 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -583,7 +583,7 @@ void ShaderParamsDialog::onShaderResetPass(int pass) reload(); } -void ShaderParamsDialog::onShaderResetParameter(int parameter) +void ShaderParamsDialog::onShaderResetParameter(QString parameter) { struct video_shader *menu_shader = NULL; struct video_shader *video_shader = NULL; @@ -594,25 +594,35 @@ void ShaderParamsDialog::onShaderResetParameter(int parameter) if (menu_shader) { struct video_shader_parameter *param = NULL; + int i; - if (parameter < 0 || parameter >= static_cast(menu_shader->num_parameters)) - return; + for (i = 0; i < static_cast(menu_shader->num_parameters); i++) + { + QString id = menu_shader->parameters[i].id; - param = &menu_shader->parameters[parameter]; + if (id == parameter) + param = &menu_shader->parameters[i]; + } - param->current = param->initial; + if (param) + param->current = param->initial; } if (video_shader) { struct video_shader_parameter *param = NULL; + int i; - if (parameter < 0 || parameter >= static_cast(video_shader->num_parameters)) - return; + for (i = 0; i < static_cast(video_shader->num_parameters); i++) + { + QString id = video_shader->parameters[i].id; - param = &video_shader->parameters[parameter]; + if (id == parameter) + param = &video_shader->parameters[i]; + } - param->current = param->initial; + if (param) + param->current = param->initial; } reload(); @@ -897,11 +907,21 @@ void ShaderParamsDialog::buildLayout() if (video_shader->passes == 0) setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); } + /* Normally we'd only use video_shader, but the vulkan driver returns a NULL shader when there + * are zero passes, so just fall back to menu_shader. + */ + else if (menu_shader) + { + avail_shader = menu_shader; + + if (menu_shader->passes == 0) + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); + } else { setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); - /* video_shader isn't available yet, just keep retrying until it is */ + /* no shader is available yet, just keep retrying until it is */ QTimer::singleShot(0, this, SLOT(buildLayout())); return; } @@ -1090,7 +1110,7 @@ void ShaderParamsDialog::buildLayout() if (param->pass != i) continue; - addShaderParam(param, j, form); + addShaderParam(param, form); } } @@ -1117,8 +1137,7 @@ void ShaderParamsDialog::onParameterLabelContextMenuRequested(const QPoint&) QList actions; QScopedPointer resetParamAction; QVariant paramVariant; - int parameter = 0; - bool ok = false; + QString parameter; label = qobject_cast(sender()); @@ -1130,10 +1149,7 @@ void ShaderParamsDialog::onParameterLabelContextMenuRequested(const QPoint&) if (!paramVariant.isValid()) return; - parameter = paramVariant.toInt(&ok); - - if (!ok) - return; + parameter = paramVariant.toString(); resetParamAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER), 0)); @@ -1197,9 +1213,10 @@ void ShaderParamsDialog::onGroupBoxContextMenuRequested(const QPoint&) } } -void ShaderParamsDialog::addShaderParam(struct video_shader_parameter *param, int parameter, QFormLayout *form) +void ShaderParamsDialog::addShaderParam(struct video_shader_parameter *param, QFormLayout *form) { QString desc = param->desc; + QString parameter = param->id; QLabel *label = new QLabel(desc); label->setProperty("parameter", parameter); @@ -1294,8 +1311,8 @@ void ShaderParamsDialog::onShaderParamCheckBoxClicked() if (paramVariant.isValid()) { + QString parameter = paramVariant.toString(); bool ok = false; - int parameter = paramVariant.toInt(&ok); if (!ok) return; @@ -1303,8 +1320,15 @@ void ShaderParamsDialog::onShaderParamCheckBoxClicked() if (menu_shader) { struct video_shader_parameter *param = NULL; + int i; - param = &menu_shader->parameters[parameter]; + for (i = 0; i < static_cast(menu_shader->num_parameters); i++) + { + QString id = menu_shader->parameters[i].id; + + if (id == parameter) + param = &menu_shader->parameters[i]; + } if (param) param->current = (checkBox->isChecked() ? param->maximum : param->minimum); @@ -1313,8 +1337,15 @@ void ShaderParamsDialog::onShaderParamCheckBoxClicked() if (video_shader) { struct video_shader_parameter *param = NULL; + int i; - param = &video_shader->parameters[parameter]; + for (i = 0; i < video_shader->num_parameters; i++) + { + QString id = video_shader->parameters[i].id; + + if (id == parameter) + param = &video_shader->parameters[i]; + } if (param) param->current = (checkBox->isChecked() ? param->maximum : param->minimum); @@ -1341,23 +1372,43 @@ void ShaderParamsDialog::onShaderParamSliderValueChanged(int) if (paramVariant.isValid()) { - bool ok = false; - int parameter = paramVariant.toInt(&ok); + QString parameter = paramVariant.toString(); - if (ok) + if (menu_shader) { - if (menu_shader) - { - struct video_shader_parameter *param = &menu_shader->parameters[parameter]; + struct video_shader_parameter *param = NULL; + int i; + for (i = 0; i < static_cast(menu_shader->num_parameters); i++) + { + QString id = menu_shader->parameters[i].id; + + if (id == parameter) + param = &menu_shader->parameters[i]; + } + + if (param) + { newValue = MainWindow::lerp(0, 100, param->minimum, param->maximum, slider->value()); param->current = newValue; } + } - if (video_shader) + if (video_shader) + { + struct video_shader_parameter *param = NULL; + int i; + + for (i = 0; i < video_shader->num_parameters; i++) { - struct video_shader_parameter *param = &video_shader->parameters[parameter]; + QString id = video_shader->parameters[i].id; + if (id == parameter) + param = &video_shader->parameters[i]; + } + + if (param) + { newValue = MainWindow::lerp(0, 100, param->minimum, param->maximum, slider->value()); param->current = newValue; } @@ -1417,28 +1468,48 @@ void ShaderParamsDialog::onShaderParamSpinBoxValueChanged(int value) if (paramVariant.isValid()) { - bool ok = false; - int parameter = paramVariant.toInt(&ok); + QString parameter = paramVariant.toString(); - if (ok) + double newValue = 0.0; + + if (menu_shader) { - double newValue = 0.0; + struct video_shader_parameter *param = NULL; + int i; - if (menu_shader) + for (i = 0; i < static_cast(menu_shader->num_parameters); i++) { - struct video_shader_parameter *param = &menu_shader->parameters[parameter]; + QString id = menu_shader->parameters[i].id; + if (id == parameter) + param = &menu_shader->parameters[i]; + } + + if (param) + { param->current = value; newValue = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); slider->blockSignals(true); slider->setValue(newValue); slider->blockSignals(false); } + } - if (video_shader) + if (video_shader) + { + struct video_shader_parameter *param = NULL; + int i; + + for (i = 0; i < video_shader->num_parameters; i++) { - struct video_shader_parameter *param = &video_shader->parameters[parameter]; + QString id = video_shader->parameters[i].id; + if (id == parameter) + param = &video_shader->parameters[i]; + } + + if (param) + { param->current = value; newValue = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); slider->blockSignals(true); @@ -1477,28 +1548,48 @@ void ShaderParamsDialog::onShaderParamDoubleSpinBoxValueChanged(double value) if (paramVariant.isValid()) { - bool ok = false; - int parameter = paramVariant.toInt(&ok); + QString parameter = paramVariant.toString(); - if (ok) + double newValue = 0.0; + + if (menu_shader) { - double newValue = 0.0; + struct video_shader_parameter *param = NULL; + int i; - if (menu_shader) + for (i = 0; i < static_cast(menu_shader->num_parameters); i++) { - struct video_shader_parameter *param = &menu_shader->parameters[parameter]; + QString id = menu_shader->parameters[i].id; + if (id == parameter) + param = &menu_shader->parameters[i]; + } + + if (param) + { param->current = value; newValue = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); slider->blockSignals(true); slider->setValue(newValue); slider->blockSignals(false); } + } - if (video_shader) + if (video_shader) + { + struct video_shader_parameter *param = NULL; + int i; + + for (i = 0; i < video_shader->num_parameters; i++) { - struct video_shader_parameter *param = &video_shader->parameters[parameter]; + QString id = video_shader->parameters[i].id; + if (id == parameter) + param = &video_shader->parameters[i]; + } + + if (param) + { param->current = value; newValue = MainWindow::lerp(param->minimum, param->maximum, 0, 100, param->current); slider->blockSignals(true); diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h index 4a0732180c..6397b743ce 100644 --- a/ui/drivers/qt/shaderparamsdialog.h +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -48,7 +48,7 @@ private slots: void onShaderPassMoveUpClicked(); void onShaderResetPass(int pass); void onShaderResetAllPasses(); - void onShaderResetParameter(int parameter); + void onShaderResetParameter(QString parameter); void onShaderLoadPresetClicked(); void onShaderAddPassClicked(); void onShaderSavePresetAsClicked(); @@ -62,7 +62,7 @@ private slots: void buildLayout(); private: QString getFilterLabel(unsigned filter); - void addShaderParam(struct video_shader_parameter *param, int parameter, QFormLayout *form); + void addShaderParam(struct video_shader_parameter *param, QFormLayout *form); void getShaders(struct video_shader **menu_shader, struct video_shader **video_shader); void saveShaderPreset(const char *path, unsigned action_type); From 49b785b9dc3e93b3235da65dd9ab52b11bdaacfd Mon Sep 17 00:00:00 2001 From: altiereslima Date: Thu, 23 Aug 2018 13:03:36 -0300 Subject: [PATCH 135/182] Update brazilian portuguese translation Added some missing strings. Aligned with msg_hash_us.h --- intl/msg_hash_pt_br.h | 10851 +++++++++++++++++++++++++++------------- 1 file changed, 7240 insertions(+), 3611 deletions(-) diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index 95d3fb5769..7bacfd3ce8 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -1,3750 +1,7379 @@ MSG_HASH( - MSG_COMPILER, - "Compilador" - ) + MSG_COMPILER, + "Compilador" + ) MSG_HASH( - MSG_UNKNOWN_COMPILER, - "Compilador desconhecido" - ) + MSG_UNKNOWN_COMPILER, + "Compilador desconhecido" + ) MSG_HASH( - MSG_DEVICE_DISCONNECTED_FROM_PORT, - "Dispositivo desconectado da porta" - ) + MSG_DEVICE_DISCONNECTED_FROM_PORT, + "Dispositivo desconectado da porta" + ) MSG_HASH( - MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, - "Comando Netplay desconhecido recebido" - ) + MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, + "Comando Netplay desconhecido recebido" + ) MSG_HASH( - MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, - "Este arquivo já existe. Salvando no buffer de backup" - ) + MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, + "Este arquivo já existe. Salvando no buffer de backup" + ) MSG_HASH( - MSG_GOT_CONNECTION_FROM, - "Conexão recebida de: \"%s\"" - ) + MSG_GOT_CONNECTION_FROM, + "Conexão recebida de: \"%s\"" + ) MSG_HASH( - MSG_GOT_CONNECTION_FROM_NAME, - "Conexão recebida de: \"%s (%s)\"" - ) + MSG_GOT_CONNECTION_FROM_NAME, + "Conexão recebida de: \"%s (%s)\"" + ) MSG_HASH( - MSG_PUBLIC_ADDRESS, - "Endereço público" - ) + MSG_PUBLIC_ADDRESS, + "Endereço público" + ) MSG_HASH( - MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, - "Nenhum argumento fornecido e nenhum menu interno, exibindo ajuda..." - ) + MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, + "Nenhum argumento fornecido e nenhum menu interno, exibindo ajuda..." + ) MSG_HASH( - MSG_SETTING_DISK_IN_TRAY, - "Definindo disco na bandeja" - ) + MSG_SETTING_DISK_IN_TRAY, + "Definindo disco na bandeja" + ) MSG_HASH( - MSG_WAITING_FOR_CLIENT, - "Aguardando pelo cliente..." - ) + MSG_WAITING_FOR_CLIENT, + "Aguardando pelo cliente..." + ) MSG_HASH( - MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME, - "Você deixou o jogo" - ) + MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME, + "Você deixou o jogo" + ) MSG_HASH( - MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, - "Você se juntou como jogador %u" - ) + MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, + "Você se juntou como jogador %u" + ) MSG_HASH( - MSG_NETPLAY_YOU_HAVE_JOINED_WITH_INPUT_DEVICES_S, - "Você se juntou aos dispositivos de entrada %.*s" - ) + MSG_NETPLAY_YOU_HAVE_JOINED_WITH_INPUT_DEVICES_S, + "Você se juntou aos dispositivos de entrada %.*s" + ) MSG_HASH( - MSG_NETPLAY_PLAYER_S_LEFT, - "O jogador %.*s deixou o jogo" - ) + MSG_NETPLAY_PLAYER_S_LEFT, + "O jogador %.*s deixou o jogo" + ) MSG_HASH( - MSG_NETPLAY_S_HAS_JOINED_AS_PLAYER_N, - "%.*s se juntou como jogador %u" - ) + MSG_NETPLAY_S_HAS_JOINED_AS_PLAYER_N, + "%.*s se juntou como jogador %u" + ) MSG_HASH( - MSG_NETPLAY_S_HAS_JOINED_WITH_INPUT_DEVICES_S, - "%.*s juntou-se a dispositivos de entrada %.*s" - ) + MSG_NETPLAY_S_HAS_JOINED_WITH_INPUT_DEVICES_S, + "%.*s juntou-se a dispositivos de entrada %.*s" + ) MSG_HASH( - MSG_NETPLAY_NOT_RETROARCH, - "Uma tentativa de conexão com o netplay falhou porque o par não está executando o RetroArch ou está executando uma versão antiga do RetroArch." - ) + MSG_NETPLAY_NOT_RETROARCH, + "Uma tentativa de conexão com o netplay falhou porque o par não está executando o RetroArch ou está executando uma versão antiga do RetroArch." + ) MSG_HASH( - MSG_NETPLAY_OUT_OF_DATE, - "O par netplay está executando uma versão antiga do RetroArch. Não pode conectar." - ) + MSG_NETPLAY_OUT_OF_DATE, + "O par netplay está executando uma versão antiga do RetroArch. Não pode conectar." + ) MSG_HASH( - MSG_NETPLAY_DIFFERENT_VERSIONS, - "ATENÇÃO: Um par de Netplay está executando uma versão diferente do RetroArch. Se ocorrerem problemas, use a mesma versão." - ) + MSG_NETPLAY_DIFFERENT_VERSIONS, + "ATENÇÃO: Um par de Netplay está executando uma versão diferente do RetroArch. Se ocorrerem problemas, use a mesma versão." + ) MSG_HASH( - MSG_NETPLAY_DIFFERENT_CORES, - "Um par de netplay está executando um núcleo diferente. Não pode conectar." - ) + MSG_NETPLAY_DIFFERENT_CORES, + "Um par de netplay está executando um núcleo diferente. Não pode conectar." + ) MSG_HASH( - MSG_NETPLAY_DIFFERENT_CORE_VERSIONS, - "ATENÇÃO: Um par de Netplay está executando uma versão diferente do núcleo. Se ocorrerem problemas, use a mesma versão." - ) + MSG_NETPLAY_DIFFERENT_CORE_VERSIONS, + "ATENÇÃO: Um par de Netplay está executando uma versão diferente do núcleo. Se ocorrerem problemas, use a mesma versão." + ) MSG_HASH( - MSG_NETPLAY_ENDIAN_DEPENDENT, - "Este núcleo não suporta Netplay inter-arquitetura entre estes sistemas" - ) + MSG_NETPLAY_ENDIAN_DEPENDENT, + "Este núcleo não suporta Netplay inter-arquitetura entre estes sistemas" + ) MSG_HASH( - MSG_NETPLAY_PLATFORM_DEPENDENT, - "Este núcleo não suporta Netplay inter-arquitetura" - ) + MSG_NETPLAY_PLATFORM_DEPENDENT, + "Este núcleo não suporta Netplay inter-arquitetura" + ) MSG_HASH( - MSG_NETPLAY_ENTER_PASSWORD, - "Digite a senha do servidor de Netplay:" - ) + MSG_NETPLAY_ENTER_PASSWORD, + "Digite a senha do servidor de Netplay:" + ) MSG_HASH( - MSG_NETPLAY_INCORRECT_PASSWORD, - "Senha incorreta" - ) + MSG_NETPLAY_INCORRECT_PASSWORD, + "Senha incorreta" + ) MSG_HASH( - MSG_NETPLAY_SERVER_NAMED_HANGUP, - "\"%s\" desconectou" - ) + MSG_NETPLAY_SERVER_NAMED_HANGUP, + "\"%s\" desconectou" + ) MSG_HASH( - MSG_NETPLAY_SERVER_HANGUP, - "Um cliente do Netplay desconectou" - ) + MSG_NETPLAY_SERVER_HANGUP, + "Um cliente do Netplay desconectou" + ) MSG_HASH( - MSG_NETPLAY_CLIENT_HANGUP, - "Desconectado do Netplay" - ) + MSG_NETPLAY_CLIENT_HANGUP, + "Desconectado do Netplay" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, - "Você não tem permissão para jogar" - ) + MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, + "Você não tem permissão para jogar" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, - "Não há vagas livres para jogadores" - ) + MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, + "Não há vagas livres para jogadores" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY_NOT_AVAILABLE, - "Os dispositivos de entrada solicitados não estão disponíveis" - ) + MSG_NETPLAY_CANNOT_PLAY_NOT_AVAILABLE, + "Os dispositivos de entrada solicitados não estão disponíveis" + ) MSG_HASH( - MSG_NETPLAY_CANNOT_PLAY, - "Impossível alterar para modo jogador" - ) + MSG_NETPLAY_CANNOT_PLAY, + "Impossível alterar para modo jogador" + ) MSG_HASH( - MSG_NETPLAY_PEER_PAUSED, - "Par do Netplay \"%s\" pausou" - ) + MSG_NETPLAY_PEER_PAUSED, + "Par do Netplay \"%s\" pausou" + ) MSG_HASH( - MSG_NETPLAY_CHANGED_NICK, - "Seu apelido mudou para \"%s\"" - ) + MSG_NETPLAY_CHANGED_NICK, + "Seu apelido mudou para \"%s\"" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, - "Dar aos núcleos renderizados por hardware seu próprio contexto privado. Evita ter que assumir mudanças de estado de hardware entre quadros." - ) + MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, + "Dar aos núcleos renderizados por hardware seu próprio contexto privado. Evita ter que assumir mudanças de estado de hardware entre quadros." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_SETTINGS, - "Ajusta as configurações de aparência da tela de menu." - ) + MENU_ENUM_SUBLABEL_MENU_SETTINGS, + "Ajusta as configurações de aparência da tela de menu." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, - "Sincronia rígida entre CPU e GPU. Reduz a latência ao custo de desempenho." - ) + MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, + "Sincronia rígida entre CPU e GPU. Reduz a latência ao custo de desempenho." + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_THREADED, - "Melhora o desempenho ao custo de latência e mais engasgamento de vídeo. Use somente se você não puder obter velocidade total de outra forma." - ) + MENU_ENUM_SUBLABEL_VIDEO_THREADED, + "Melhora o desempenho ao custo de latência e mais engasgamento de vídeo. Use somente se você não puder obter velocidade total de outra forma." + ) MSG_HASH( - MSG_AUDIO_VOLUME, - "Volume de áudio" - ) + MSG_AUDIO_VOLUME, + "Volume de áudio" + ) MSG_HASH( - MSG_AUTODETECT, - "Detectar automaticamente" - ) + MSG_AUTODETECT, + "Detectar automaticamente" + ) MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Autocarregando Estado de Jogo de" - ) + MSG_AUTOLOADING_SAVESTATE_FROM, + "Autocarregando Estado de Jogo de" + ) MSG_HASH( - MSG_CAPABILITIES, - "Capacidades" - ) + MSG_CAPABILITIES, + "Capacidades" + ) MSG_HASH( - MSG_CONNECTING_TO_NETPLAY_HOST, - "Conectando ao hospedeiro de Netplay" - ) + MSG_CONNECTING_TO_NETPLAY_HOST, + "Conectando ao hospedeiro de Netplay" + ) MSG_HASH( - MSG_CONNECTING_TO_PORT, - "Conectando a porta" - ) + MSG_CONNECTING_TO_PORT, + "Conectando a porta" + ) MSG_HASH( - MSG_CONNECTION_SLOT, - "Vaga de conexão" - ) + MSG_CONNECTION_SLOT, + "Vaga de conexão" + ) MSG_HASH( - MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, - "Desculpe, não implementado: núcleos que não exigem conteúdo não podem participar do Netplay." - ) + MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, + "Desculpe, não implementado: núcleos que não exigem conteúdo não podem participar do Netplay." + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, - "Senha" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, + "Senha" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, - "Contas Cheevos" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, + "Contas Cheevos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, - "Nome de usuário" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, + "Nome de usuário" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, - "Contas" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, + "Contas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, - "Ponto Final da Lista de Contas" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, + "Ponto Final da Lista de Contas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, - "Retro Achievements" - ) + MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, + "Retro Achievements" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, - "Lista de Conquistas" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, + "Lista de Conquistas" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE, - "Pausar Conquistas no Modo Hardcore" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE, + "Pausar Conquistas no Modo Hardcore" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME, - "Contiuar Conquistas no Modo Hardcore" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME, + "Contiuar Conquistas no Modo Hardcore" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "Lista de Conquistas (Hardcore)" - ) + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, + "Lista de Conquistas (Hardcore)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, - "Analisar Conteúdo" - ) + MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, + "Analisar Conteúdo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, - "Configurações" - ) + MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, + "Configurações" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ADD_TAB, - "Importar conteúdo" - ) + MENU_ENUM_LABEL_VALUE_ADD_TAB, + "Importar conteúdo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, - "Salas de Netplay" - ) + MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, + "Salas de Netplay" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, - "Perguntar" - ) + MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, + "Perguntar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, - "Recursos" - ) + MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, + "Recursos" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, - "Bloquear Quadros" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, + "Bloquear Quadros" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, - "Dispositivo de Áudio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, + "Dispositivo de Áudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, - "Driver de Áudio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, + "Driver de Áudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, - "Plugin DSP de Áudio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, + "Plugin DSP de Áudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, - "Habilitar Áudio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, + "Habilitar Áudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, - "Filtro de Áudio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, + "Filtro de Áudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, - "Turbo/Zona-Morta" - ) + MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, + "Turbo/Zona-Morta" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, - "Latência de Áudio (ms)" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, + "Latência de Áudio (ms)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, - "Desvio Máximo de Tempo do Áudio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, + "Desvio Máximo de Tempo do Áudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, - "Áudio Mudo" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, + "Áudio Mudo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, - "Taxa da Saída de Áudio (Hz)" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, + "Taxa da Saída de Áudio (Hz)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, - "Controle Dinâmico da Taxa de Áudio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, + "Controle Dinâmico da Taxa de Áudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, - "Driver de Reamostragem de Áudio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, + "Driver de Reamostragem de Áudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, - "Áudio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, + "Áudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, - "Sincronizar Áudio" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, + "Sincronizar Áudio" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, - "Nível de Volume de Áudio (dB)" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, + "Nível de Volume de Áudio (dB)" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_EXCLUSIVE_MODE, - "WASAPI Modo Exclusivo" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_EXCLUSIVE_MODE, + "WASAPI Modo Exclusivo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_FLOAT_FORMAT, - "WASAPI Formato de Ponto Flutuante" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_FLOAT_FORMAT, + "WASAPI Formato de Ponto Flutuante" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_SH_BUFFER_LENGTH, - "WASAPI Tamanho do Buffer Compartilhado" - ) + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_SH_BUFFER_LENGTH, + "WASAPI Tamanho do Buffer Compartilhado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, - "Intervalo do Salvamento Automático da SRAM" - ) + MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, + "Intervalo do Salvamento Automático da SRAM" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, - "Carrega Automaticamente Arquivos de Redefinição" - ) + MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, + "Carrega Automaticamente Arquivos de Redefinição" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, - "Carrega Automaticamente Arquivos de Remapeamento" - ) + MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, + "Carrega Automaticamente Arquivos de Remapeamento" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, - "Carrega Automaticamente Predefinições de Shader" - ) + MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, + "Carrega Automaticamente Predefinições de Shader" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, - "Voltar" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, + "Voltar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, - "Confirmar" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, + "Confirmar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, - "Informações" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, + "Informações" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, - "Sair" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, + "Sair" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, - "Rolar para Baixo" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, + "Rolar para Baixo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, - "Rolar para Cima" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, + "Rolar para Cima" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, - "Iniciar" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, + "Iniciar" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, - "Alternar Teclado" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, + "Alternar Teclado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, - "Alternar Menu" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, + "Alternar Menu" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, - "Controles Básicos de Menu" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, + "Controles Básicos de Menu" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, - "Confirmar/OK" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, + "Confirmar/OK" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, - "Informação" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, + "Informação" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, - "Sair" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, + "Sair" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, - "Rolar para Cima" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, + "Rolar para Cima" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, - "Padrões" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, + "Padrões" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_KEYBOARD, - "Alternar Teclado" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_KEYBOARD, + "Alternar Teclado" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, - "Alternar Menu" - ) + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, + "Alternar Menu" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, - "Não sobregravar a SRAM ao carregar Estado de Jogo" - ) + MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, + "Não sobregravar a SRAM ao carregar Estado de Jogo" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, - "Habilitar Bluetooth" - ) + MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, + "Habilitar Bluetooth" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, - "URL de Recursos do Buildbot" - ) + MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, + "URL de Recursos do Buildbot" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, - "Cache" - ) + MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, + "Cache" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, - "Permitir Câmera" - ) + MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, + "Permitir Câmera" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, - "Driver de Câmera" - ) + MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, + "Driver de Câmera" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT, - "Trapaça" - ) + MENU_ENUM_LABEL_VALUE_CHEAT, + "Trapaça" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, - "Aplicar Alterações" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, + "Aplicar Alterações" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, - "Arquivo de Trapaça" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_START_SEARCH, + "Iniciar Pesquisa Por um Novo Código de Trapaça" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE, - "Arquivo de Trapaça" - ) + MENU_ENUM_LABEL_VALUE_CHEAT_CONTINUE_SEARCH, + "Continuar Pesquisa" + ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, - "Carregar Arquivo de Trapaça" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, - "Salvar Arquivo de Trapaça Como" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, - "Estágios de Trapaça" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, - "Descrição" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, - "Conquistas no Modo Hardcore" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_LEADERBOARDS_ENABLE, - "Tabelas de Classificação" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_BADGES_ENABLE, - "Insígnias de Conquistas" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, - "Conquistas Bloqueadas:" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY, - "Bloqueada" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_SETTINGS, - "Retro Achievements" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, - "Testar Conquistas Não Oficiais" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, - "Conquistas Desbloqueadas:" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY, - "Desbloqueada" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, - "Hardcore" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_VERBOSE_ENABLE, - "Modo Detalhado das Conquistas" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CHEEVOS_AUTO_SCREENSHOT, - "Captura de Conquistas Automática" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, - "Fechar Conteúdo" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIG, - "Configuração" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, - "Carregar Configuração" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, - "Configuração" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, - "Salvar Configuração ao Sair" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST, - "Coleções" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, - "Base de Dados" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_DIR, - "Conteúdo" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, - "Tamanho da Lista de Histórico") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, - "Permitir a remoção de itens") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, - "Menu Rápido") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, - "Recursos de Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, - "Downloads") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, - "Trapaças") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, - "Contadores do Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ENABLE, - "Exibir nome do núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, - "Informação do Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, - "Autores") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, - "Categorias") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL, - "Rótulo do núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME, - "Nome do núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, - "Firmware(s)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, - "Licença(s)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, - "Permissões") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS, - "Extensões suportadas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_MANUFACTURER, - "Fabricante do sistema") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, - "Nome do sistema") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, - "Controles") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_LIST, - "Carregar Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, - "Opções") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SETTINGS, - "Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SET_SUPPORTS_NO_CONTENT_ENABLE, - "Iniciar um Núcleo Automaticamente") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, - "Extrair automaticamente o arquivo baixado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, - "URL de Núcleos do Buildbot") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST, - "Atualizador de Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, - "Atualizador") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CPU_ARCHITECTURE, - "Arquitetura da CPU:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CPU_CORES, - "Cores da CPU:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CURSOR_DIRECTORY, - "Cursor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CURSOR_MANAGER, - "Gerenciar Cursor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO, - "Proporção Personalizada") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER, - "Gerenciar Base de Dados") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_SELECTION, - "Seleção de Base de Dados") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DELETE_ENTRY, - "Remover") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FAVORITES, - "Diretório Inicial") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, - "Diretório não encontrado.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS, - "Diretório") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS, - "Condição da Bandeja do Ciclo de Disco") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, - "Anexar Imagem de Disco") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_INDEX, - "Índice de Disco") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, - "Controle de Disco") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DONT_CARE, - "Não importa") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, - "Downloads") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE, - "Baixar Núcleo...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT, - "Download de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_ENABLE, - "Habilitar Redefinição de DPI") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_VALUE, - "Redefinição de DPI") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, - "Driver") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, - "Carregar Modelo no Desligamento do Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, - "Verificar por Firmware que Falta Antes de Carregar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, - "Plano de Fundo Dinâmico") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, - "Planos de Fundo Dinâmicos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, - "Habilitar Conquistas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, - "Cor do item de menu ao passar o cursor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, - "Cor normal do item de menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FALSE, - "Falso") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, - "Velocidade Máxima de Execução") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, - "Favoritos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FPS_SHOW, - "Mostrar Taxa de Quadros") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, - "Controlar Velocidade Máxima de Execução") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, - "Controle de Quadros") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, - "Contadores do Frontend") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, - "Carrega Automaticamente Opções de Núcleo Específicas do Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, - "Criar arquivo de opções do jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, - "Salvar arquivo de opções do jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP, - "Ajuda") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, - "Solução de Problemas de Áudio/Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, - "Alterando a Transparência de Gamepad Virtual") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, - "Controles Básicos de Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LIST, - "Ajuda") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, - "Carregando Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, - "Procurando em Busca de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, - "O Que É Um Núcleo?") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, - "Habilitar Lista de Histórico") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_TAB, - "Histórico") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, - "Menu Horizontal") -MSG_HASH(MENU_ENUM_LABEL_VALUE_IMAGES_TAB, - "Imagem") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION, - "Informação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, - "Informação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, - "Tipo de Analógico Para Digital") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, - "Todos os Usuários Controlam o Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, - "Analógico Esquerdo X") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, - "Analógico Esquerdo X- (esquerda)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, - "Analógico Esquerdo X+ (direita)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y, - "Analógico Esquerdo Y") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, - "Analógico Esquerdo Y- (cima)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, - "Analógico Esquerdo Y+ (baixo)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X, - "Analógico Direito X") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, - "Analógico Direito X- (esquerda)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, - "Analógico Direito X+ (direita)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y, - "Analógico Direito Y") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, - "Analógico Direito Y- (cima)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, - "Analógico Direito Y+ (baixo)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, - "Gatinho da Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, - "Recarregar Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A, - "Aux A da Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B, - "Aux B da Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C, - "Aux C da Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START, - "Start da Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT, - "Select da Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP, - "D-pad Cima da Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN, - "D-pad Baixo da Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT, - "D-pad Esquerdo da Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, - "D-pad Direito da Pistola") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, - "Habilitar Autoconfiguração") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, - "Zona Morta do Controle Analógico") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, - "Inverter Botões OK e Cancelar do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, - "Vincular Todos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, - "Vincular Todos pelo Padrão") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_TIMEOUT, - "Tempo Limite para Vincular") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_HIDE_UNBOUND, - "Ocultar Descritores de Entrada do Núcleo Não Vinculados") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW, - "Exibir Rótulos do Descritor de Entrada") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, - "Índice de Dispositivo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, - "Tipo de Dispositivo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, - "Índice de Mouse") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DRIVER, - "Driver de Entrada") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Ciclo de Trabalho") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, - "Vínculos das Teclas de Atalho da Entrada") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, - "Habilitar Mapeamento de Gamepad no Teclado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, - "Botão A (direita)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, - "Botão B (baixo)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, - "Direcional para baixo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, - "Botão L2 (gatilho)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, - "Botão L3 (polegar)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, - "Botão L (ombro)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, - "Direcional Esquerdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, - "Botão R2 (gatilho)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, - "Botão R3 (polegar)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, - "Botão R (ombro)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, - "Direcional Direito") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, - "Botão Select") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, - "Botão Start") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, - "Direcional para Cima") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, - "Botão X (topo)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, - "Botão Y (esquerda)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEY, - "(Tecla: %s)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_LEFT, - "Mouse 1") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_RIGHT, - "Mouse 2") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_MIDDLE, - "Mouse 3") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON4, - "Mouse 4") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON5, - "Mouse 5") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_UP, - "Roda do Mouse para Cima") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_DOWN, - "Roda do Mouse para Baixo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_UP, - "Roda do Mouse para Esquerda") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_DOWN, - "Roda do Mouse para Direita") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, - "Tipo de Mapeamento para Gamepad no Teclado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, - "Usuários Máximos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Combinação do Gamepad para Alternar Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, - "Índice de Trapaça -") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, - "Índice de Trapaça +") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, - "Alternar Trapaça") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, - "Alternar ejeção de disco") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, - "Próximo disco") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, - "Disco anterior") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, - "Habilitar teclas de atalho") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, - "Manter Avanço Rápido") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, - "Alternar Avanço Rápido") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, - "Avanço de Quadro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, - "Alternar tela cheia") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, - "Alternar captura do Mouse") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, - "Alternar foco do jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, - "Alternar menu desktop") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, - "Carregar Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, - "Alternar menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, - "Alternar gravação de filme") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, - "Alternar áudio mudo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, - "Alternar modo jogador/espectador do Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, - "Alternar teclado virtual") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, - "Próxima Transparência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, - "Alternar pausa") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, - "Sair do RetroArch") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, - "Reiniciar jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, - "Rebobinar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, - "Salvar Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, - "Capturar tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, - "Próximo Shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, - "Shader Anterior") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY, - "Câmera Lenta") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY, - "Alternar câmera lenta") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, - "Compartimento do Estado de Jogo -") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, - "Compartimento do Estado de Jogo +") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, - "Volume -") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, - "Volume +") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, - "Mostrar Transparência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, - "Ocultar Transparência no Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, - "Exibir Comandos Na Transparência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, - "Porta de Escuta do Exibir Comandos ") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, - "Tipo de Comportamento da Chamada Seletiva") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, - "Mais cedo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_LATE, - "Mais tarde") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_NORMAL, - "Normal") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_PREFER_FRONT_TOUCH, - "Preferir Toque Frontal") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, - "Remapeamento de Entrada") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, - "Habilitar Remapeamento de Vínculos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, - "Salvar Autoconfiguração") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, - "Entrada") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, - "Habilitar Teclado Pequeno") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_ENABLE, - "Habilitar Toque") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "Habilitar Turbo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, - "Período do Turbo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, - "Vínculos de Entrada do Usuário %u") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LATENCY_SETTINGS, - "Latência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INTERNAL_STORAGE_STATUS, - "Condição do armazenamento interno") -MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, - "Autoconfiguração de Entrada") -MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, - "Driver de Joypad") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, - "Serviços") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_CHINESE_SIMPLIFIED, - "Chinês (Simplificado)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_CHINESE_TRADITIONAL, - "Chinês (Tradicional)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_DUTCH, - "Holandês") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ENGLISH, - "Inglês") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ESPERANTO, - "Esperanto") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_FRENCH, - "Francês") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_GERMAN, - "Alemão") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ITALIAN, - "Italiano") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_JAPANESE, - "Japonês") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_KOREAN, - "Coreano") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_POLISH, - "Polonês") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_BRAZIL, - "Português (Brasil)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_PORTUGAL, - "Português (Portugal)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_RUSSIAN, - "Russo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH, - "Espanhol") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE, - "Vietnamita") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC, - "Árabe") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, - "Analógico Esquerdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, - "Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, - "Informação do Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, - "Nível de Registro de Eventos do Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LINEAR, - "Linear") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, - "Carregar Arquivo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, - "Carregar Recente") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, - "Carregar Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_STATE, - "Carregar Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, - "Permitir Localização") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER, - "Driver de Localização") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, - "Registro de Eventos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY, - "Verbosidade do Registro de Eventos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MAIN_MENU, - "Menu Principal") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MANAGEMENT, - "Configurações da Base de Dados") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, - "Tema de Cor do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE, - "Azul") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, - "Cinza Azulado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_DARK_BLUE, - "Azul Escuro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GREEN, - "Verde") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_NVIDIA_SHIELD, - "Shield") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_RED, - "Vermelho") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_YELLOW, - "Amarelo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, - "Opacidade do Rodapé") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, - "Opacidade do Cabeçalho") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_DRIVER, - "Driver de Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, - "Controlar Taxa de Quadros do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, - "Configurações") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, - "Filtro Linear de Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, - "Animação Horizontal") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Aparência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, - "Plano de Fundo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, - "Opacidade do plano de fundo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MISSING, - "Faltando") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MORE, - "...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MOUSE_ENABLE, - "Suporte para Mouse") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MULTIMEDIA_SETTINGS, - "Multimídia") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MUSIC_TAB, - "Música") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, - "Filtrar Extensões Desconhecidas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, - "Navegação Retorna ao Início") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NEAREST, - "Mais Próximo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY, - "Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_SLAVES, - "Permitir Clientes em Modo Escravo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, - "Verificar Quadros do Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, - "Quadros de Latência de Entrada") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, - "Faixa de Quadros de Latência de Entrada") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, - "Atraso de Quadros do Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, - "Desconectar do hospedeiro de Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, - "Habilitar Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, - "Conectar ao hospedeiro de Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, - "Iniciar hospedeiro de Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, - "Parar hospedeiro de Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, - "Endereço do Servidor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, - "Analisar a rede local") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, - "Habilitar Cliente Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, - "Usuário") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, - "Senha do Servidor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, - "Anunciar Netplay Publicamente") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REQUEST_DEVICE_I, - "Solicitar Dispositivo %u") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REQUIRE_SLAVES, - "Não Permitir Clientes em Modo Não Escravo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, - "Configurações do Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG, - "Compartilhamento de Entrada Analógica") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_MAX, - "Máximo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_AVERAGE, - "Médio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL, - "Compartilhamento de Entrada Digital") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_OR, - "Compartilhar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_XOR, - "Agarrar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_VOTE, - "Eleger") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NONE, - "Nenhum") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NO_PREFERENCE, - "Sem preferência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_AS_SPECTATOR, - "Modo Espectador do Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, - "Modo sem Estados de Jogo do Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, - "Senha Apenas Espectador do Servidor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, - "Habilitar Espectador do Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, - "Porta TCP do Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, - "Travessia de NAT do Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, - "Comandos de Rede") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, - "Porta de Comando de Rede") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION, - "Informação de Rede") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, - "Gamepad de Rede") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, - "Porta Base Remota de Rede") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, - "Rede") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO, - "Não") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NONE, - "Nenhum") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE, - "N/D") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY, - "Não há Conquistas para mostrar.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE, - "Nenhum Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, - "Nenhum núcleo disponível") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, - "Não há informação de núcleo disponível.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, - "Não há opções de núcleo disponíveis.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, - "Não há itens para mostrar.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, - "Não há histórico disponível.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, - "Não há informação disponível.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ITEMS, - "Sem itens.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, - "Nenhum hospedeiro de Netplay encontrado.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, - "Nenhuma rede encontrada.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, - "Não há contadores de desempenho.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, - "Não há listas de reprodução.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, - "Não há itens de lista de reprodução disponível.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, - "Nenhuma configuração encontrada.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, - "Não há parâmetros de Shader.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OFF, - "DESLIGADO") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ON, - "LIGADO") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ONLINE, - "Online") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, - "Atualizador Online") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, - "Exibição na Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, - "Transparência na Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, - "Notificações na Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, - "Navegar no Arquivo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OPTIONAL, - "Opcional") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY, - "Transparência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, - "Carrega Automaticamente Transparência Favorita") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, - "Transparência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, - "Opacidade da Transparência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, - "Predefinição de Transparência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, - "Escala da Transparência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, - "Transparência na Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, - "Utilizar Modo PAL60") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, - "Diretório superior") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, - "Pausar quando o menu for ativado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE, - "Não rodar em segundo plano") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE, - "Contadores de Desempenho") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB, - "Listas de Reprodução") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, - "Lista de Reprodução") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, - "Listas de Reprodução") -MSG_HASH(MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, - "Suporte para Toque") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PORT, - "Porta") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PRESENT, - "Presente") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS, - "Privacidade") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, - "Sair do RetroArch") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG, - "Analógico suportado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, - "Classificação BBFC") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CERO_RATING, - "Classificação CERO") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_COOP, - "Cooperativo suportado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CRC32, - "CRC32") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DESCRIPTION, - "Descrição") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER, - "Desenvolvedor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, - "Edição da Revista Edge") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING, - "Classificação da Revista Edge") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_REVIEW, - "Análise da Revista Edge") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ELSPA_RATING, - "Classificação ELSPA") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, - "Hardware de Aprimoramento") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ESRB_RATING, - "Classificação ESRB") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FAMITSU_MAGAZINE_RATING, - "Classificação da Revista Famitsu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE, - "Franquia") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GENRE, - "Gênero") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MD5, - "MD5") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME, - "Nome") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ORIGIN, - "Origem") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PEGI_RATING, - "Classificação PEGI") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, - "Editor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, - "Mês de Lançamento") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, - "Ano de Lançamento") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RUMBLE, - "Suporte para Vibração") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SERIAL, - "Número de Série") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1, - "SHA1") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, - "Iniciar Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, - "Classificação TGDB") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REBOOT, - "Reiniciar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, - "Configuração de Gravação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, - "Saída de Gravação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS, - "Gravação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, - "Carregar Configuração de Gravação...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, - "Driver de Gravação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, - "Habilitar Gravação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_PATH, - "Salvar Saída de Gravação Como...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, - "Salvar Gravações no Diretório de Saída") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE, - "Arquivo de Remapeamento") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, - "Carregar Arquivo de Remapeamento") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, - "Salvar Arquivo de Remapeamento de Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CONTENT_DIR, - "Salvar Arquivo de Remapeamento de Jogo do Diretório de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, - "Salvar Arquivo de Remapeamento de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE, - "Excluir Arquivo de Remapeamento de Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME, - "Excluir Arquivo de Remapeamento de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CONTENT_DIR, - "Excluir Arquivo de Remapeamento de Jogo do Diretório de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REQUIRED, - "Obrigatório") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, - "Reiniciar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_RETROARCH, - "Reiniciar RetroArch") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RESUME, - "Retomar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, - "Retomar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, - "RetroKeyboard") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD, - "RetroPad") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, - "RetroPad com Analógico") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, - "Conquistas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_ENABLE, - "Habilitar Rebobinagem") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_GRANULARITY, - "Granularidade da Rebobinagem") -MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, - "Rebobinagem") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Navegador de Arquivos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, - "Configuração") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, - "Mostrar Tela Inicial") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, - "Analógico Direito") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, - "Adicionar aos Favoritos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES_PLAYLIST, - "Adicionar aos Favoritos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RESET_CORE_ASSOCIATION, - "Redefinir Associação do Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN, - "Executar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_MUSIC, - "Executar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, - "Habilitar SAMBA") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, - "Arquivo de Jogo-Salvo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, - "Índice Automático de Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, - "Carrega Automaticamente Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, - "Salvar Automaticamente Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, - "Arquivo de Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, - "Miniaturas do Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, - "Salvar Configuração Atual") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, - "Salvar Redefinição de Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, - "Salvar Redefinições do Diretório de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, - "Salvar Redefinição de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, - "Salvar Nova Configuração") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_STATE, - "Salvar Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, - "Salvando") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, - "Analisar Diretório") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_FILE, - "Analisar Arquivo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, - "Captura de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, - "Resolução da Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SEARCH, - "Procurar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SECONDS, - "segundos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS, - "Configurações") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, - "Configurações") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER, - "Shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, - "Aplicar Alterações") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS, - "Shaders") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON, - "Faixa") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON_SIMPLIFIED, - "Faixa (simplificada)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SIMPLE_SNOW, - "Neve Simples") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOW, - "Neve") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, - "Exibir Configurações Avançadas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, - "Exibir Arquivos e Pastas Ocultos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHUTDOWN, - "Desligar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, - "Taxa de Câmera Lenta") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_ENABLED, - "Adiantar Quadro para Reduzir a Latência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_FRAMES, - "Número de Quadros para Adiantar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_SECONDARY_INSTANCE, - "O Adiantamento de Quadro Usará uma Segunda Instância") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_HIDE_WARNINGS, - "Ocultar Avisos do Adiantamento de Quadro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, - "Classificar Arquivos de Jogo-Salvo em Pastas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, - "Classificar Arquivos de Estado de Jogo em Pastas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE, - "Gravar Estados de Jogo no Diretório de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE, - "Gravar Jogos-Salvos no Diretório de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, - "Arquivos de Sistema estão no Diretório de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, - "Salvar Capturas de Tela no Diretório de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SSH_ENABLE, - "Habilitar SSH") -MSG_HASH(MENU_ENUM_LABEL_VALUE_START_CORE, - "Iniciar Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD, - "Iniciar RetroPad Remoto") -MSG_HASH(MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, - "Iniciar Processador de Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_STATE_SLOT, - "Compartimento do Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_STATUS, - "Condição") -MSG_HASH(MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE, - "Comandos stdin") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SUPPORTED_CORES, - "Núcleos Sugeridos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SUSPEND_SCREENSAVER_ENABLE, - "Desativar Protetor de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE, - "Habilitar Música em Segundo Plano do Sistema") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, - "Sistema/BIOS") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, - "Informação do Sistema") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT, - "Suporte a 7zip") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT, - "Suporte a ALSA") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_BUILD_DATE, - "Data de Compilação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CG_SUPPORT, - "Suporte a Cg") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COCOA_SUPPORT, - "Suporte a Cocoa") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COMMAND_IFACE_SUPPORT, - "Suporte à Interface de Comando") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CORETEXT_SUPPORT, - "Suporte a CoreText") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CPU_FEATURES, - "Características de CPU") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_DPI, - "Métrica DPI da Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT, - "Métrica de Altura da Tela (mm)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH, - "Métrica de Largura da Tela (mm)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DSOUND_SUPPORT, - "Suporte a DirectSound") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT, - "Suporte a WASAPI") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, - "Suporte à biblioteca dinâmica") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, - "Carregamento dinâmico em tempo de execução da biblioteca libretro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT, - "Suporte a EGL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT, - "Suporte a OpenGL/Direct3D render-to-texture (multi-pass shaders)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FFMPEG_SUPPORT, - "Suporte a FFmpeg") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FREETYPE_SUPPORT, - "Suporte a FreeType") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER, - "Identificador do Frontend") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_NAME, - "Nome do Frontend") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_OS, - "SO do Frontend") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GIT_VERSION, - "Versão Git") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GLSL_SUPPORT, - "Suporte a GLSL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_HLSL_SUPPORT, - "Suporte a HLSL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_JACK_SUPPORT, - "Suporte a JACK") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_KMS_SUPPORT, - "Suporte a KMS/EGL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LAKKA_VERSION, - "Versão Lakka") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBRETRODB_SUPPORT, - "Suporte a LibretroDB") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, - "Suporte a Libusb") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBXML2_SUPPORT, - "Suporte a libxml2 XML parsing") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, - "Suporte Netplay (ponto-a-ponto)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, - "Suporte à Interface de comando de rede") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_REMOTE_SUPPORT, - "Suporte a Gamepad de Rede") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT, - "Suporte a OpenAL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT, - "Suporte a OpenGL ES") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGL_SUPPORT, - "Suporte a OpenGL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENSL_SUPPORT, - "Suporte a OpenSL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENVG_SUPPORT, - "Suporte a OpenVG") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OSS_SUPPORT, - "Suporte a OSS") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OVERLAY_SUPPORT, - "Suporte à Transparência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE, - "Fonte de Energia") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGED, - "Carregado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGING, - "Carregando") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_DISCHARGING, - "Descarregando") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE, - "Não há fonte") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, - "Suporte a PulseAudio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PYTHON_SUPPORT, - "Suporte a Python (suporte de script em Shaders)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RBMP_SUPPORT, - "Suporte a BMP (RBMP)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RETRORATING_LEVEL, - "Nível RetroRating") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RJPEG_SUPPORT, - "Suporte a JPEG (RJPEG)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ROARAUDIO_SUPPORT, - "Suporte a RoarAudio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RPNG_SUPPORT, - "Suporte a PNG (RPNG)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RSOUND_SUPPORT, - "Suporte a RSound") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RTGA_SUPPORT, - "Suporte a TGA (RTGA)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, - "Suporte a SDL2") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_IMAGE_SUPPORT, - "Suporte a imagem SDL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_SUPPORT, - "Suporte a SDL1.2") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SLANG_SUPPORT, - "Suporte a Slang") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_THREADING_SUPPORT, - "Suporte a Paralelismo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, - "Suporte a Udev") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, - "Suporte a Video4Linux2") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER, - "Driver de contexto de vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, - "Suporte a Vulkan") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT, - "Suporte a Wayland") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_X11_SUPPORT, - "Suporte a X11") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XAUDIO2_SUPPORT, - "Suporte a XAudio2") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT, - "Suporte a XVideo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT, - "Suporte a Zlib") -MSG_HASH(MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, - "Capturar tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, - "Paralelismo de tarefas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS, - "Miniaturas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS, - "Miniaturas à Esquerda") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_VERTICAL_THUMBNAILS, - "Disposição Vertical de Miniaturas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, - "Miniaturas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, - "Atualizador de Miniaturas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, - "Arte da Embalagem") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, - "Captura de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, - "Telas do Título") -MSG_HASH(MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, - "Exibir data e hora") -MSG_HASH(MENU_ENUM_LABEL_VALUE_TITLE_COLOR, - "Cor do título do menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_TRUE, - "Verdadeiro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, - "Habilitar Companheiro da Interface de Usuário") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, - "Companheiro da Interface de Usuário Roda na Inicialização") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_TOGGLE, - "Mostrar menu desktop na inicialização") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DESKTOP_MENU_ENABLE, - "Habilitar menu desktop (reiniciar)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, - "Barra de Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE, - "Incapaz de ler o arquivo comprimido.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, - "Desfazer Carregamento de Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, - "Desfazer Salvamento de Estado de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UNKNOWN, - "Desconhecido") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, - "Atualizador") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, - "Atualizar Recursos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "Atualizar Perfis de Autoconfiguração") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, - "Atualizar Shaders Cg") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, - "Atualizar Trapaças") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, - "Atualizar Arquivos de Informação de Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, - "Atualizar Bases de Dados") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, - "Atualizar Shaders GLSL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, - "Atualizar Lakka") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, - "Atualizar Transparências") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_SLANG_SHADERS, - "Atualizar Shaders Slang") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USER, - "Usuário") -MSG_HASH(MENU_ENUM_LABEL_VALUE_KEYBOARD, - "Kbd") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS, - "Interface de Usuário") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_LANGUAGE, - "Idioma") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_SETTINGS, - "Usuário") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Utilizar o Visualizador de Imagem Integrado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Utilizar o Reprodutor de Mídia Integrado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, - "Permitir rotação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO, - "Configurar Proporção de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, - "Proporção de Tela Automática") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, - "Proporção de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, - "Inserção de Quadro Opaco") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, - "Cortar Overscan (Recarregar)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, - "Desativar Composição da Área de Trabalho") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER, - "Driver de Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER, - "Filtro de Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, - "Filtro de Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, - "Filtro de tremulação de vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, - "Habilitar Notificações na Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, - "Fonte das Notificações na Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, - "Tamanho da Notificação na Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, - "Forçar Proporção de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE, - "Forçar Desativação de sRGB FBO") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, - "Atraso de Quadro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, - "Utilizar Modo de Tela Cheia") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, - "Gama de Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, - "Usar Gravação da GPU") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, - "Habilitar Captura de Tela da GPU") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC, - "Sincronia Rígida de GPU") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC_FRAMES, - "Quadros de Sincronia Rígida de GPU") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, - "Máximo de imagens na cadeia de troca") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, - "Posição X da Notificação na Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, - "Posição Y da Notificação na Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, - "Índice de Monitor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, - "Usar Gravação Pós-Filtro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, - "Taxa de Atualização Vertical") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, - "Taxa de Quadros Estimada da Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_POLLED, - "Definir Taxa de Atualização Reportada") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ROTATION, - "Rotação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE, - "Escala em Janela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, - "Escala em Inteiros") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, - "Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, - "Shader de Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, - "Estágios de Shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, - "Pré-visualizar Parâmetros de Shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, - "Carregar Predefinição de Shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, - "Salvar Predefinição de Shader Como") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, - "Salvar Predefinição de Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT, - "Salvar Predefinição do Diretório de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, - "Salvar Predefinição de Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, - "Habilitar Contexto Compartilhado de Hardware") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, - "Filtragem Bilinear") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, - "Habilitar Filtro por Software") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, - "Intervalo de Troca da Sincronização Vertical (V-Sync)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_TAB, - "Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, - "Vídeo Paralelizado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, - "Reduzir Tremulação de Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "Altura Personalizada da Proporção de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "Largura Personalizada da Proporção de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, - "Posição X Personalizada da Proporção de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, - "Posição Y Personalizada da Proporção de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, - "Definir Largura de Tela do VI") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, - "Sincronização Vertical (V-Sync)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, - "Modo Janela em Tela Cheia") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, - "Largura da Janela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, - "Altura da Janela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_X, - "Largura em Tela Cheia") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_Y, - "Altura em Tela Cheia") -MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, - "Driver de Wi-Fi") -MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, - "Wi-Fi") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, - "Fator Alfa do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_RED, - "Cor Vermelha da Fonte do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_GREEN, - "Cor Verde da Fonte do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_BLUE, - "Cor Azul da Fonte do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_FONT, - "Fonte do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, - "Personalizado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, - "FlatUI") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME, - "Monocromático") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME_INVERTED, - "Monocromático Invertido") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_SYSTEMATIC, - "Sistemático") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_NEOACTIVE, - "NeoActive") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_PIXEL, - "Pixel") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, - "RetroActive") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROSYSTEM, - "Retrosystem") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, - "Dot-Art") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, - "Tema de Cor do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_APPLE_GREEN, - "Verde Maçã") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK, - "Escuro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LIGHT, - "Claro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MORNING_BLUE, - "Azul da manhã") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK_PURPLE, - "Roxo Escuro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ELECTRIC_BLUE, - "Azul Elétrico") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GOLDEN, - "Dourado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LEGACY_RED, - "Vermelho Legado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDNIGHT_BLUE, - "Azul Meia-noite") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_PLAIN, - "Natural") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, - "Submarino") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, - "Vermelho Vulcânico") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, - "Pipeline do Shader de Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, - "Fator de Escala do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, - "Habilitar Sombras dos Ícones") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_HISTORY, - "Exibir Aba de Histórico") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, - "Exibir Aba de Importação de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, - "Exibir Abas de Lista de Reprodução") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_FAVORITES, - "Exibir Aba de Favoritos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_IMAGES, - "Exibir Aba de Imagem") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_MUSIC, - "Exibir Aba de Música") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS, - "Exibir Aba de Configurações") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO, - "Exibir Aba de Vídeo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, - "Exibir Aba de Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_LAYOUT, - "Layout do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_THEME, - "Tema de Ícones do Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_YES, - "Sim") -MSG_HASH(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, - "Predefinição de Shader") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, - "Habilitar ou desabilitar conquistas. Para mais informações, visite http://retroachievements.org") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, - "Habilitar ou desabilitar conquistas não oficiais e/ou recursos beta para fins de teste.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, - "Habilitar ou desabilitar Estado de Jogo, Trapaças, Rebobinagem, Avanço Rápido, Pausa e Câmera Lenta para todos os jogos.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_LEADERBOARDS_ENABLE, - "Habilitar ou desabilitar tabelas de classificação no jogo. Não tem efeito se o modo Hardcore estiver desativado.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_BADGES_ENABLE, - "Habilitar ou desabilitar a exibição de insígnia na Lista de Conquistas.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE, - "Habilitar ou desabilitar detalhes das conquistas na tela.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_AUTO_SCREENSHOT, - "Obter automaticamente uma captura de tela quando uma conquista é acionada.") -MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, - "Alterar os drivers utilizados pelo sistema.") -MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "Alterar as configurações de conquistas.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_SETTINGS, - "Alterar as configurações de núcleo.") -MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, - "Alterar as configurações de gravação.") -MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, - "Alterar as configurações de Transparência e Transparência de teclado, e as configurações de notificação na tela.") -MSG_HASH(MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, - "Alterar as configurações de Rebobinagem, Avanço Rápido e Câmera Lenta.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVING_SETTINGS, - "Alterar as configurações de salvamento.") -MSG_HASH(MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, - "Alterar as configurações de registro de eventos.") -MSG_HASH(MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, - "Alterar as configurações da interface de usuário.") -MSG_HASH(MENU_ENUM_SUBLABEL_USER_SETTINGS, - "Alterar as configurações de conta, nome de usuário e idioma.") -MSG_HASH(MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, - "Alterar as configurações de privacidade.") -MSG_HASH(MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, - "Alterar os diretórios padrão onde os arquivos estão localizados.") -MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, - "Alterar as configurações de lista de reprodução.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, - "Configurar as configurações de servidor e rede.") -MSG_HASH(MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, - "Analisar conteúdo e adicionar na base de dados.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, - "Alterar as configurações de saída de áudio.") -MSG_HASH(MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, - "Habilitar ou desabilitar o bluetooth.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, - "Salvar as alterações nos arquivos de configuração ao sair.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, - "Alterar as definições padrão para os arquivos de configuração.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, - "Gerenciar e criar arquivos de configuração.") -MSG_HASH(MENU_ENUM_SUBLABEL_CPU_CORES, - "Quantidade de Cores que a CPU possui.") -MSG_HASH(MENU_ENUM_SUBLABEL_FPS_SHOW, - "Exibir a taxa atual de quadros por segundo na tela.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, - "Ajustar configurações das teclas de atalho.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Combinação de botões do Gamepad para alternar o menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_SETTINGS, - "Alterar as configurações de Joypad, teclado e Mouse.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, - "Configurar os controles para este usuário.") -MSG_HASH(MENU_ENUM_SUBLABEL_LATENCY_SETTINGS, - "Altere as configurações relacionadas a vídeo, áudio e latência dos comandos.") -MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, - "Habilitar ou desabilitar registro de eventos no terminal.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, - "Juntar-se ou hospedar uma sessão de Netplay.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, - "Procurar por e conectar aos hospedeiros de Netplay na rede local.") -MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Exibir informações de núcleo, rede e sistema.") -MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, - "Baixar complementos, componentes e conteúdo para o RetroArch.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, - "Habilitar ou desabilitar compartilhamento de pastas na rede.") -MSG_HASH(MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, - "Gerenciar serviços ao nível de sistema operacional.") -MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, - "Exibir arquivos/diretórios ocultos no navegador de arquivos.") -MSG_HASH(MENU_ENUM_SUBLABEL_SSH_ENABLE, - "Habilitar ou desabilitar acesso remoto à linha de comando.") -MSG_HASH(MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, - "Prevenir que o protetor de tela do seu sistema seja ativado.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, - "Definir o tamanho da janela em relação ao tamanho da janela de exibição do núcleo. Como alternativa, você pode definir uma largura e altura de janela abaixo para um tamanho de janela fixo.") -MSG_HASH(MENU_ENUM_SUBLABEL_USER_LANGUAGE, - "Definir o idioma da interface.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Inserir um quadro opaco entre quadros. Útil para usuários com telas de 120Hz que desejam jogar conteúdos em 60Hz para eliminar efeito de fantasma.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, - "Reduz a latência ao custo de maior risco de engasgamento de vídeo. Adiciona um atraso após o V-Sync (em ms).") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, - "Definir quantos quadros a CPU pode rodar à frente da GPU quando utilizado o recurso 'Sincronia Rígida de GPU'.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, - "Informar ao driver de vídeo para utilizar explicitamente um modo de buffer específico.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, - "Seleciona qual tela de exibição a ser usada.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, - "A taxa de atualização estimada da tela em Hz.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_POLLED, - "A taxa de atualização conforme relatada pelo driver de vídeo.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, - "Alterar as configurações de saída de vídeo.") -MSG_HASH(MENU_ENUM_SUBLABEL_WIFI_SETTINGS, - "Analisar por redes sem fio e estabelecer uma conexão.") -MSG_HASH(MENU_ENUM_SUBLABEL_HELP_LIST, - "Saiba mais sobre como o programa funciona.") -MSG_HASH(MSG_ADDED_TO_FAVORITES, - "Adicionado aos favoritos") -MSG_HASH(MSG_RESET_CORE_ASSOCIATION, - "A associação do núcleo de entrada da lista de reprodução foi redefinida.") -MSG_HASH(MSG_APPENDED_DISK, - "Disco anexado") -MSG_HASH(MSG_APPLICATION_DIR, - "Diretório do aplicativo") -MSG_HASH(MSG_APPLYING_CHEAT, - "Aplicando as alterações de Trapaças.") -MSG_HASH(MSG_APPLYING_SHADER, - "Aplicando Shader") -MSG_HASH(MSG_AUDIO_MUTED, - "Áudio mudo.") -MSG_HASH(MSG_AUDIO_UNMUTED, - "Áudio mudo desativado.") -MSG_HASH(MSG_AUTOCONFIG_FILE_ERROR_SAVING, - "Erro em salvar o arquivo de autoconfiguração.") -MSG_HASH(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, - "Arquivo de autoconfiguração salvo com sucesso.") -MSG_HASH(MSG_AUTOSAVE_FAILED, - "Não foi possível inicializar o salvamento automático.") -MSG_HASH(MSG_AUTO_SAVE_STATE_TO, - "Salvar Automaticamente Estado de Jogo em") -MSG_HASH(MSG_BLOCKING_SRAM_OVERWRITE, - "Bloqueando Sobrescrita da SRAM") -MSG_HASH(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, - "Trazendo a interface de comando na porta") -MSG_HASH(MSG_BYTES, - "bytes") -MSG_HASH(MSG_CANNOT_INFER_NEW_CONFIG_PATH, - "Não é possível inferir o novo caminho de configuração. Use a hora atual.") -MSG_HASH(MSG_CHEEVOS_HARDCORE_MODE_ENABLE, - "Modo Hardcore Habilitado, Estados de Jogo e Rebobinagem estão desabilitados.") -MSG_HASH(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, - "Comparando com números mágicos conhecidos...") -MSG_HASH(MSG_COMPILED_AGAINST_API, - "Compilado contra a API") -MSG_HASH(MSG_CONFIG_DIRECTORY_NOT_SET, - "Diretório de configuração não definido. Não foi possível salvar a nova configuração.") -MSG_HASH(MSG_CONNECTED_TO, - "Conectado a") -MSG_HASH(MSG_CONTENT_CRC32S_DIFFER, - "O CRC32 dos conteúdos difere. Não é possível utilizar jogos diferentes.") -MSG_HASH(MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, - "Carregamento de conteúdo ignorado. A implementação irá carregar por conta própria.") -MSG_HASH(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "O núcleo não suporta Estados de Jogo.") -MSG_HASH(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, - "O arquivo de opções de núcleo foi criado com sucesso.") -MSG_HASH(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, - "Não foi possível encontrar nenhum driver seguinte") -MSG_HASH(MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, - "Não foi possível encontrar um sistema compatível.") -MSG_HASH(MSG_COULD_NOT_FIND_VALID_DATA_TRACK, - "Não foi possível encontrar uma faixa de dados válida") -MSG_HASH(MSG_COULD_NOT_OPEN_DATA_TRACK, - "Não foi possível abrir a faixa de dados") -MSG_HASH(MSG_COULD_NOT_READ_CONTENT_FILE, - "Não foi possível ler o arquivo de conteúdo") -MSG_HASH(MSG_COULD_NOT_READ_MOVIE_HEADER, - "Não foi possível ler o cabeçalho do filme.") -MSG_HASH(MSG_COULD_NOT_READ_STATE_FROM_MOVIE, - "Não foi possível ler o Estado de Jogo do filme.") -MSG_HASH(MSG_CRC32_CHECKSUM_MISMATCH, - "Soma de verificação CRC32 incompatível entre o arquivo de conteúdo e a soma de verificação de conteúdo salva no cabeçalho do arquivo de reprodução. Reprodução altamente susceptível de dessincronizar na reprodução.") -MSG_HASH(MSG_CUSTOM_TIMING_GIVEN, - "Tempo personalizado fornecido") -MSG_HASH(MSG_DECOMPRESSION_ALREADY_IN_PROGRESS, - "Descompressão já está em andamento.") -MSG_HASH(MSG_DECOMPRESSION_FAILED, - "Descompressão falhou.") -MSG_HASH(MSG_DETECTED_VIEWPORT_OF, - "Detectada janela de exibição de") -MSG_HASH(MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, - "Não encontrou uma modificação de conteúdo válido.") -MSG_HASH(MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, - "Desconectar dispositivo de uma porta válida.") -MSG_HASH(MSG_DISK_CLOSED, - "Fechado") -MSG_HASH(MSG_DISK_EJECTED, - "Ejetado") -MSG_HASH(MSG_DOWNLOADING, - "Baixando") -MSG_HASH(MSG_INDEX_FILE, - "index") -MSG_HASH(MSG_DOWNLOAD_FAILED, - "Download falhou") -MSG_HASH(MSG_ERROR, - "Erro") -MSG_HASH(MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, - "O núcleo libretro requer conteúdo, mas nada foi fornecido.") -MSG_HASH(MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT, - "O núcleo libretro requer conteúdo especial, mas nenhum foi fornecido.") -MSG_HASH(MSG_ERROR_PARSING_ARGUMENTS, - "Erro em analisar os argumentos.") -MSG_HASH(MSG_ERROR_SAVING_CORE_OPTIONS_FILE, - "Erro em salvar o arquivo de opções de núcleo.") -MSG_HASH(MSG_ERROR_SAVING_REMAP_FILE, - "Erro em salvar o arquivo de remapeamento.") -MSG_HASH(MSG_ERROR_REMOVING_REMAP_FILE, - "Erro em remover o arquivo de remapeamento.") -MSG_HASH(MSG_ERROR_SAVING_SHADER_PRESET, - "Erro em salvar a predefinição de Shader.") -MSG_HASH(MSG_EXTERNAL_APPLICATION_DIR, - "Diretório de Aplicativo Externo") -MSG_HASH(MSG_EXTRACTING, - "Extraindo") -MSG_HASH(MSG_EXTRACTING_FILE, - "Extraindo arquivo") -MSG_HASH(MSG_FAILED_SAVING_CONFIG_TO, - "Falha em salvar a configuração em") -MSG_HASH(MSG_FAILED_TO, - "Falha em") -MSG_HASH(MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, - "Falha em aceitar o espectador ingresso.") -MSG_HASH(MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, - "Falha em alocar memória para o conteúdo modificado...") -MSG_HASH(MSG_FAILED_TO_APPLY_SHADER, - "Falha em aplicar o Shader.") -MSG_HASH(MSG_FAILED_TO_BIND_SOCKET, - "Falha em vincular o soquete.") -MSG_HASH(MSG_FAILED_TO_CREATE_THE_DIRECTORY, - "Falha em criar o diretório.") -MSG_HASH(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, - "Falha em extrair o conteúdo do arquivo comprimido") -MSG_HASH(MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, - "Falha em obter o apelido do cliente.") -MSG_HASH(MSG_FAILED_TO_LOAD, - "Falha em carregar") -MSG_HASH(MSG_FAILED_TO_LOAD_CONTENT, - "Falha em carregar o conteúdo") -MSG_HASH(MSG_FAILED_TO_LOAD_MOVIE_FILE, - "Falha em carregar o arquivo de filme") -MSG_HASH(MSG_FAILED_TO_LOAD_OVERLAY, - "Falha em carregar a Transparência.") -MSG_HASH(MSG_FAILED_TO_LOAD_STATE, - "Falha em carregar o Estado de Jogo de") -MSG_HASH(MSG_FAILED_TO_OPEN_LIBRETRO_CORE, - "Falha em abrir o núcleo Libretro") -MSG_HASH(MSG_FAILED_TO_PATCH, - "Falha em executar a modificação") -MSG_HASH(MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT, - "Falha em receber o cabeçalho do cliente.") -MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME, - "Falha em receber o apelido.") -MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST, - "Falha em receber o apelido do hospedeiro.") -MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_SIZE_FROM_HOST, - "Falha em receber o tamanho do apelido do hospedeiro.") -MSG_HASH(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST, - "Falha em receber os dados SRAM do hospedeiro.") -MSG_HASH(MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY, - "Falha em remover o disco da bandeja.") -MSG_HASH(MSG_FAILED_TO_REMOVE_TEMPORARY_FILE, - "Falha em remover o arquivo temporário") -MSG_HASH(MSG_FAILED_TO_SAVE_SRAM, - "Falha em salvar SRAM") -MSG_HASH(MSG_FAILED_TO_SAVE_STATE_TO, - "Falha em salvar o Estado de Jogo em") -MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME, - "Falha em enviar o apelido.") -MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_SIZE, - "Falha em enviar o tamanho do apelido.") -MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT, - "Falha em enviar o apelido para o cliente.") -MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, - "Falha em enviar o apelido para o hospedeiro.") -MSG_HASH(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, - "Falha em enviar os dados SRAM para o cliente.") -MSG_HASH(MSG_FAILED_TO_START_AUDIO_DRIVER, - "Falha em iniciar o driver de áudio. Prosseguindo sem áudio.") -MSG_HASH(MSG_FAILED_TO_START_MOVIE_RECORD, - "Falha em iniciar a gravação do filme.") -MSG_HASH(MSG_FAILED_TO_START_RECORDING, - "Falha em iniciar a gravação.") -MSG_HASH(MSG_FAILED_TO_TAKE_SCREENSHOT, - "Falha em obter uma captura de tela.") -MSG_HASH(MSG_FAILED_TO_UNDO_LOAD_STATE, - "Falha em desfazer o carregamento de Estado de Jogo.") -MSG_HASH(MSG_FAILED_TO_UNDO_SAVE_STATE, - "Falha em desfazer o salvamento de Estado de Jogo.") -MSG_HASH(MSG_FAILED_TO_UNMUTE_AUDIO, - "Falha em desativar o áudio mudo.") -MSG_HASH(MSG_FATAL_ERROR_RECEIVED_IN, - "Erro fatal recebido em") -MSG_HASH(MSG_FILE_NOT_FOUND, - "Arquivo não encontrado") -MSG_HASH(MSG_FOUND_AUTO_SAVESTATE_IN, - "Estado de Jogo automático encontrado em") -MSG_HASH(MSG_FOUND_DISK_LABEL, - "Rótulo de disco encontrado") -MSG_HASH(MSG_FOUND_FIRST_DATA_TRACK_ON_FILE, - "Encontrada primeira faixa de dados no arquivo") -MSG_HASH(MSG_FOUND_LAST_STATE_SLOT, - "Encontrada último compartimento de Estado de Jogo") -MSG_HASH(MSG_FOUND_SHADER, - "Shader encontrado") -MSG_HASH(MSG_FRAMES, - "Quadros") -MSG_HASH(MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT, - "Opções por Jogo: Opções de núcleo específicas do jogo encontradas em") -MSG_HASH(MSG_GOT_INVALID_DISK_INDEX, - "Índice de disco inválido obtido") -MSG_HASH(MSG_GRAB_MOUSE_STATE, - "Capturar estado do Mouse") -MSG_HASH(MSG_GAME_FOCUS_ON, - "Foco do jogo ligado") -MSG_HASH(MSG_GAME_FOCUS_OFF, - "Foco do jogo desligado") -MSG_HASH(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, - "O núcleo libretro é renderizado por hardware. Deve usar a gravação pós-Shader também.") -MSG_HASH(MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, - "A soma de verificação inflada não corresponde ao CRC32.") -MSG_HASH(MSG_INPUT_CHEAT, - "Entrada de Trapaça") -MSG_HASH(MSG_INPUT_CHEAT_FILENAME, - "Nome do Arquivo de Trapaça") -MSG_HASH(MSG_INPUT_PRESET_FILENAME, - "Nome de Arquivo de Predefinição") -MSG_HASH(MSG_INPUT_RENAME_ENTRY, - "Renomear Título") -MSG_HASH(MSG_INTERFACE, - "Interface") -MSG_HASH(MSG_INTERNAL_STORAGE, - "Armazenamento Interno") -MSG_HASH(MSG_REMOVABLE_STORAGE, - "Armazenamento Removível") -MSG_HASH(MSG_INVALID_NICKNAME_SIZE, - "Tamanho de apelido inválido.") -MSG_HASH(MSG_IN_BYTES, - "em bytes") -MSG_HASH(MSG_IN_GIGABYTES, - "em gigabytes") -MSG_HASH(MSG_IN_MEGABYTES, - "em megabytes") -MSG_HASH(MSG_LIBRETRO_ABI_BREAK, - "foi compilado contra uma versão diferente do libretro do que esta.") -MSG_HASH(MSG_LIBRETRO_FRONTEND, - "Frontend para Libretro") -MSG_HASH(MSG_LOADED_STATE_FROM_SLOT, - "Estado de Jogo carregado do compartimento #%d.") -MSG_HASH(MSG_LOADED_STATE_FROM_SLOT_AUTO, - "Estado de Jogo carregado do compartimento #-1 (automático).") -MSG_HASH(MSG_LOADING, - "Carregando") -MSG_HASH(MSG_FIRMWARE, - "Um ou mais arquivos de firmware estão faltando") -MSG_HASH(MSG_LOADING_CONTENT_FILE, - "Carregando arquivo de conteúdo") -MSG_HASH(MSG_LOADING_HISTORY_FILE, - "Carregando arquivo de histórico") -MSG_HASH(MSG_LOADING_STATE, - "Carregando Estado de Jogo") -MSG_HASH(MSG_MEMORY, - "Memória") -MSG_HASH(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, - "O arquivo de filme não é um arquivo BSV1 válido.") -MSG_HASH(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, - "O formato de filme parece ter uma versão de serializador diferente. Provavelmente irá falhar.") -MSG_HASH(MSG_MOVIE_PLAYBACK_ENDED, - "Reprodução de filme terminou.") -MSG_HASH(MSG_MOVIE_RECORD_STOPPED, - "Parando a gravação de filme.") -MSG_HASH(MSG_NETPLAY_FAILED, - "Falha em inicializar o Netplay.") -MSG_HASH(MSG_NO_CONTENT_STARTING_DUMMY_CORE, - "Sem conteúdo, iniciando um núcleo modelo.") -MSG_HASH(MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, - "Nenhum Estado de Jogo foi sobrescrito até o momento.") -MSG_HASH(MSG_NO_STATE_HAS_BEEN_LOADED_YET, - "Nenhum Estado de Jogo foi carregado até o momento.") -MSG_HASH(MSG_OVERRIDES_ERROR_SAVING, - "Erro em salvar as redefinições.") -MSG_HASH(MSG_OVERRIDES_SAVED_SUCCESSFULLY, - "Redefinições salvas com sucesso.") -MSG_HASH(MSG_PAUSED, - "Pausado.") -MSG_HASH(MSG_PROGRAM, - "RetroArch") -MSG_HASH(MSG_READING_FIRST_DATA_TRACK, - "Lendo a primeira faixa de dados...") -MSG_HASH(MSG_RECEIVED, - "recebido") -MSG_HASH(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, - "A gravação terminou devido ao redimensionamento.") -MSG_HASH(MSG_RECORDING_TO, - "Gravando em") -MSG_HASH(MSG_REDIRECTING_CHEATFILE_TO, - "Redirecionando o arquivo de Trapaça em") -MSG_HASH(MSG_REDIRECTING_SAVEFILE_TO, - "Redirecionando o Jogo-Salvo em") -MSG_HASH(MSG_REDIRECTING_SAVESTATE_TO, - "Redirecionando o Estado de Jogo em") -MSG_HASH(MSG_REMAP_FILE_SAVED_SUCCESSFULLY, - "Arquivo de remapeamento salvo com sucesso.") -MSG_HASH(MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, - "Arquivo de remapeamento salvo com sucesso.") -MSG_HASH(MSG_REMOVED_DISK_FROM_TRAY, - "Disco removido da bandeja.") -MSG_HASH(MSG_REMOVING_TEMPORARY_CONTENT_FILE, - "Removendo arquivo de conteúdo temporário") -MSG_HASH(MSG_RESET, - "Reinicializar") -MSG_HASH(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT, - "Reiniciando a gravação devido ao reinício do driver.") -MSG_HASH(MSG_RESTORED_OLD_SAVE_STATE, - "Estado de Jogo antigo restaurado.") -MSG_HASH(MSG_RESTORING_DEFAULT_SHADER_PRESET_TO, - "Shaders: restaurando predefinição padrão de Shader em") -MSG_HASH(MSG_REVERTING_SAVEFILE_DIRECTORY_TO, - "Revertendo diretório de Jogo-Salvo em") -MSG_HASH(MSG_REVERTING_SAVESTATE_DIRECTORY_TO, - "Revertendo diretório de Estado de Jogo em") -MSG_HASH(MSG_REWINDING, - "Voltando atrás.") -MSG_HASH(MSG_REWIND_INIT, - "Inicializando o buffer de Rebobinagem com tamanho") -MSG_HASH(MSG_REWIND_INIT_FAILED, - "Falha em inicializar o buffer de Rebobinagem. Rebobinagem será desativado.") -MSG_HASH(MSG_REWIND_INIT_FAILED_THREADED_AUDIO, - "Esta implementação usa áudio paralelizado. Não é possível utilizar Rebobinagem.") -MSG_HASH(MSG_REWIND_REACHED_END, - "Final do buffer de Rebobinagem atingido.") -MSG_HASH(MSG_SAVED_NEW_CONFIG_TO, - "Nova configuração salva em") -MSG_HASH(MSG_SAVED_STATE_TO_SLOT, - "Estado de Jogo salvo no compartimento #%d.") -MSG_HASH(MSG_SAVED_STATE_TO_SLOT_AUTO, - "Estado de Jogo salvo no compartimento #-1 (automático).") -MSG_HASH(MSG_SAVED_SUCCESSFULLY_TO, - "Salvo com sucesso em") -MSG_HASH(MSG_SAVING_RAM_TYPE, - "Salvando Tipo de RAM") -MSG_HASH(MSG_SAVING_STATE, - "Salvando Estado de Jogo") -MSG_HASH(MSG_SCANNING, - "Analisando") -MSG_HASH(MSG_SCANNING_OF_DIRECTORY_FINISHED, - "Análise de diretório terminada") -MSG_HASH(MSG_SENDING_COMMAND, - "Enviando comando") -MSG_HASH(MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED, - "Várias modificações de conteúdo estão explicitamente definidas, ignorando todas...") -MSG_HASH(MSG_SHADER, - "Shader") -MSG_HASH(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, - "Predefinição de Shader salva com sucesso.") -MSG_HASH(MSG_SKIPPING_SRAM_LOAD, - "Ignorando carregamento da SRAM.") -MSG_HASH(MSG_SLOW_MOTION, - "Câmera Lenta.") -MSG_HASH(MSG_FAST_FORWARD, - "Avanço rápido.") -MSG_HASH(MSG_SLOW_MOTION_REWIND, - "Rebobinagem em Câmera Lenta.") -MSG_HASH(MSG_SRAM_WILL_NOT_BE_SAVED, - "SRAM não será salva.") -MSG_HASH(MSG_STARTING_MOVIE_PLAYBACK, - "Iniciando reprodução de filme.") -MSG_HASH(MSG_STARTING_MOVIE_RECORD_TO, - "Iniciando a gravação de filme em") -MSG_HASH(MSG_STATE_SIZE, - "Tamanho do Estado de Jogo") -MSG_HASH(MSG_STATE_SLOT, - "Compartimento do Estado de Jogo") -MSG_HASH(MSG_TAKING_SCREENSHOT, - "Fazendo captura de tela") -MSG_HASH(MSG_TO, - "em") -MSG_HASH(MSG_UNDID_LOAD_STATE, - "Desfez o carregamento de Estado de Jogo.") -MSG_HASH(MSG_UNDOING_SAVE_STATE, - "Desfazendo o salvamento de Estado de Jogo") -MSG_HASH(MSG_UNKNOWN, - "Desconhecido") -MSG_HASH(MSG_UNPAUSED, - "Retomando.") -MSG_HASH(MSG_UNRECOGNIZED_COMMAND, - "Comando não reconhecido") -MSG_HASH(MSG_USING_CORE_NAME_FOR_NEW_CONFIG, - "Usando o nome do núcleo para uma nova configuração.") -MSG_HASH(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, - "Usando o núcleo libretro modelo. Pulando a gravação.") -MSG_HASH(MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, - "Conecte o dispositivo a partir de uma porta válida.") -MSG_HASH(MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, - "Desconectando o dispositivo da porta") -MSG_HASH(MSG_VALUE_REBOOTING, - "Reinicializando...") -MSG_HASH(MSG_VALUE_SHUTTING_DOWN, - "Desligando...") -MSG_HASH(MSG_VERSION_OF_LIBRETRO_API, - "Versão da API libretro") -MSG_HASH(MSG_VIEWPORT_SIZE_CALCULATION_FAILED, - "Falha no cálculo de tamanho da janela de exibição! Prosseguindo usando dados brutos. Isto provavelmente não funcionará corretamente...") -MSG_HASH(MSG_VIRTUAL_DISK_TRAY, - "bandeja de disco virtual.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_LATENCY, - "Latência de áudio desejada em milissegundos. Pode não ser honrado se o driver de áudio não puder prover a latência desejada.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MUTE, - "Áudio mudo/não-mudo.") -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, - "Ajuda a suavizar as imperfeições na regulagem ao sincronizar áudio e vídeo. Esteja ciente que se desativado, será quase impossível de se obter a sincronia adequada." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CAMERA_ALLOW, - "Permitir ou não o acesso à câmera pelos núcleos." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LOCATION_ALLOW, - "Permitir ou não o acesso ao serviço de localização pelos núcleos." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, - "Número máximo de usuários suportados pelo RetroArch." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, - "Influencia como a chamada seletiva de entrada é feita dentro do RetroArch. Definindo com 'Cedo' ou 'Tarde' pode resultar em menos latência, dependendo da sua configuração." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, - "Permitir a qualquer usuário controlar o menu. Se desabilitado, apenas o Usuário 1 poderá controlar o menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_VOLUME, - "Volume do áudio (em dB). 0dB é o volume normal, e nenhum ganho é aplicado." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_WASAPI_EXCLUSIVE_MODE, - "Permitir ao driver WASAPI obter controle exclusivo do dispositivo de áudio. Se desativado, o modo compartilhado será utilizado." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_WASAPI_FLOAT_FORMAT, - "Utilizar formato de ponto flutuante para o driver WASAPI, se suportado pelo dispositivo de áudio." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH, - "O tamanho (em quadros) do buffer intermediário quando o driver WASAPI estiver em modo compartilhado." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_SYNC, - "Sincroniza o áudio. Recomendado." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, - "Até que ponto um eixo deve ser movido para resultar em um botão pressionado." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, - "Quantidade de segundos para aguardar até proceder para o próximo vínculo." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Descreve o período quando os botões com turbo habilitado são alternados. Os números são descritos em quadros." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Descreve quão longo deve ser o período de um botão com turbo habilitado. Os números são descritos como quadros." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VSYNC, - "Sincroniza o vídeo de saída da placa gráfica com a taxa de atualização da tela. Recomendado." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, - "Permite que os núcleos definam a rotação. Quando desabilitado, as requisições de rotação são ignoradas. Útil para configurações onde se rotaciona manualmente a tela." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN, - "Alguns núcleos podem ter um recurso de desligamento. Se habilitado, impedirá que o núcleo feche o RetroArch. Em vez disto, carrega um núcleo modelo." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, - "Verifica se todos os firmwares necessários estão presentes antes de tentar carregar conteúdo." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, - "Taxa de atualização vertical da sua tela. Utilizado para calcular uma taxa de saída de áudio adequada. OBS: Isto será ignorado se a função 'Vídeo Paralelizado' estiver habilitada." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_ENABLE, - "Habilita a saída de áudio." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, - "Mudança máxima na taxa de entrada de áudio. Se aumentado habilita grandes mudanças na regulagem ao custo de imprecisão no timbre do som (ex: rodando núcleos PAL em modo NTSC)." - ) -MSG_HASH( - MSG_FAILED, - "falhou" - ) -MSG_HASH( - MSG_SUCCEEDED, - "teve êxito" - ) -MSG_HASH( - MSG_DEVICE_NOT_CONFIGURED, - "não configurado" - ) -MSG_HASH( - MSG_DEVICE_NOT_CONFIGURED_FALLBACK, - "não configurado, usando reserva" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, - "Lista de Cursores da Base de Dados" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DEVELOPER, - "Base de Dados - Filtro : Desenvolvedor" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PUBLISHER, - "Base de Dados - Filtro : Publicador" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISABLED, - "Desabilitado" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ENABLED, - "Habilitado" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_PATH, - "Caminho do Histórico de Conteúdo" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ORIGIN, - "Base de Dados - Filtro : Origem") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_FRANCHISE, - "Base de Dados - Filtro : Franquia") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ESRB_RATING, - "Base de Dados - Filtro : Classificação ESRB") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ELSPA_RATING, - "Base de Dados - Filtro : Classificação ELSPA") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PEGI_RATING, - "Base de Dados - Filtro : Classificação PEGI") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_CERO_RATING, - "Base de Dados - Filtro : Classificação CERO") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_BBFC_RATING, - "Base de Dados - Filtro : Classificação BBFC") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_MAX_USERS, - "Base de Dados - Filtro : Usuários máximos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_MONTH, - "Base de Dados - Filtro : Data de Lançamento Por Mês") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_YEAR, - "Base de Dados - Filtro : Data de Lançamento Por Ano") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, - "Base de Dados - Filtro : Edição da Revista Edge") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, - "Base de Dados - Filtro : Classificação da Revista Edge") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, - "Informações da Base de Dados") -MSG_HASH(MSG_WIFI_SCAN_COMPLETE, - "Análise de Wi-Fi completa.") -MSG_HASH(MSG_SCANNING_WIRELESS_NETWORKS, - "Analisando redes sem fio...") -MSG_HASH(MSG_NETPLAY_LAN_SCAN_COMPLETE, - "Análise de Netplay completa.") -MSG_HASH(MSG_NETPLAY_LAN_SCANNING, - "Analisando por hospedeiros de Netplay...") -MSG_HASH(MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, - "Pausar o jogo quando a janela do RetroArch não estiver ativa.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, - "Habilitar ou desabilitar composição (Somente no Windows).") -MSG_HASH(MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, - "Habilitar ou desabilitar a lista de reprodução recente para jogos, imagens, música e vídeos.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, - "Limita o número de itens da lista de reprodução recente para jogos, imagens, música e vídeos.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, - "Controles de Menu Unificados") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, - "Utilizar os mesmos controles para o menu e jogo. Aplica-se ao teclado.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, - "Exibir mensagens na tela.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, - "Habilitar Remoto do Usuário %d") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, - "Exibir nível de bateria") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FILE, - "Selecionar Arquivo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FROM_COLLECTION, - "Selecionar de Coleção") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER, - "Filtro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SCALE, - "Escala") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, - "O Netplay irá iniciar quando o conteúdo for carregado.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, - "Não foi possível encontrar um núcleo adequado ou arquivo de conteúdo, carregue manualmente.") -MSG_HASH( - MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, - "Navegar pela URL" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_BROWSE_URL, - "Caminho da URL" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_BROWSE_START, - "Iniciar" - ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, - "Bokeh") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOWFLAKE, - "Floco de neve") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, - "Atualizar Lista de Salas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, - "Apelido: %s") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, - "Apelido (lan): %s") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, - "Conteúdo compatível encontrado") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, - "Corta alguns pixels ao redor das bordas da imagem habitualmente deixada em branco por desenvolvedores, que por vezes também contêm pixels de lixo.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, - "Adiciona um leve embaciado à imagem para suavizar as arestas da borda dos pixels. Esta opção tem pouco impacto no desempenho.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FILTER, - "Aplica um filtro de vídeo processado pela CPU. OBS: Pode vir a um alto custo de desempenho. Alguns filtros de vídeo podem funcionar apenas para núcleos que usam cores de 32 bits ou 16 bits.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, - "Insira o nome de usuário de sua conta Retro Achievements.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, - "Insira a senha de sua conta Retro Achievements.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, - "Insira seu nome de usuário aqui. Isto será utilizado para sessões do Netplay, entre outras coisas.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, - "Capturar a imagem depois que os filtros (mas não os Shaders) forem aplicados. Seu vídeo ficará tão elegante quanto o que você vê na tela.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_LIST, - "Selecionar qual núcleo utilizar.") -MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, - "Selecionar qual conteúdo iniciar.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, - "Exibir interfaces de rede e endereços de IP associados.") -MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, - "Exibir informações específicas do dispositivo.") -MSG_HASH(MENU_ENUM_SUBLABEL_QUIT_RETROARCH, - "Sair do programa.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, - "Define a largura personalizada para a janela de exibição. Deixado em 0 a janela irá dimensionar o mais largo possível.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, - "Define a altura personalizada para a janela de exibição. Deixado em 0 a janela irá dimensionar o mais alto possível.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, - "Define a largura personalizada para o modo de tela cheia em não-janela. Deixar em 0 irá usar a resolução da área de trabalho.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, - "Define a altura personalizada para o modo de tela cheia em não-janela. Deixar em 0 irá usar a resolução da área de trabalho.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, - "Especifique a posição personalizada no eixo X para o texto na tela.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, - "Especifique a posição personalizada no eixo Y para o texto na tela.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Especifique o tamanho da fonte em pontos.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, - "Ocultar a Transparência enquanto estiver dentro do menu e exibir novamente ao sair.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, - "Exibir comandos de teclado/controle na transparência.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, - "Selecione a porta para a transparência escutar se Exibir Comandos na Transparência estiver habilitado.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, - "O conteúdo analisado aparecerá aqui." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, - "Apenas dimensiona o vídeo em valores inteiros. O tamanho de base depende da geometria relatada pelo sistema e da proporção de tela. Se 'Forçar Proporção' não estiver definido, X / Y serão dimensionados independentemente em valores inteiros." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_GPU_SCREENSHOT, - "Captura a tela com Shader de GPU se disponível." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_ROTATION, - "Força uma certa rotação da tela. A rotação é adicionada a rotação que o núcleo definir." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FORCE_SRGB_DISABLE, - "Desabilita de forma forçada o suporte sRGB FBO. Alguns drivers Intel OpenGL no Windows possuem problemas de vídeo com o suporte sRGB FBO se estiver habilitado. Habilitando isto pode contornar o problema." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN, - "Inicia em tela cheia. Pode ser mudado a qualquer momento." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_WINDOWED_FULLSCREEN, - "Se estiver em tela cheia, prefira utilizar uma janela de tela cheia." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_GPU_RECORD, - "Grava o material de saída do Shader de GPU se disponível." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, - "Ao criar um Estado de Jogo, o índice do Estado de Jogo é aumentado automaticamente antes de ser salvo. Ao carregar um conteúdo, o índice será definido para o índice mais alto existente." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, - "Bloqueia a SRAM de ser sobrescrita ao carregar um Estado de Jogo. Pode causar problemas no jogo." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_FASTFORWARD_RATIO, - "Taxa máxima em que o conteúdo será executado quando utilizado o Avanço Rápido (ex: 5.0x para conteúdos em 60fps = 300 fps máx). Se for definido como 0.0x, a taxa de Avanço Rápido é ilimitada (sem FPS máx)." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, - "Quando está em Câmera Lenta, o conteúdo será diminuído pelo fator especificado/definido." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_ENABLED, - "Executar o núcleo lógico um ou mais quadros à frente e carreguar o estado de volta para reduzir o atraso dos controles percebido." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_FRAMES, - "O número de quadros para avançar. Causa problemas de jogabilidade, como instabilidade, se você exceder o número de quadros de atraso internos do jogo." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_SECONDARY_INSTANCE, - "Usa uma segunda instância do núcleo do RetroArch para avançar quadros. Evita problemas de áudio devido ao estado de carregamento." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS, - "Oculta a mensagem de aviso que aparece ao usar o Adiantar Quadro e o núcleo não suporta Estados de Jogo." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_REWIND_ENABLE, - "Habilita a Rebobinagem. Isso irá impactar o desempenho ao jogar." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, - "Ao definir um número de quadros para Rebobinagem, você pode retroceder vários quadros de uma só vez, aumentando a velocidade da função." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, - "Define o nível de registro de eventos para os núcleos. Se o nível do registro enviado por um núcleo for abaixo deste valor, o mesmo é ignorado." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_PERFCNT_ENABLE, - "Habilitar os contadores de desempenho para o RetroArch (e núcleos)." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Cria automaticamente um Estado de Jogo no final da execução do RetroArch. O RetroArch irá carregar automaticamente este Estado de Jogo se a função 'Autocarregar Estado de Jogo' estiver habilitada." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, - "Carrega automaticamente o último Estado de Jogo auto salvo na inicialização do RetroArch." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE, - "Mostrar miniaturas de estados salvos dentro do menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, - "Salvar automaticamente o Save RAM não-volátil em um intervalo regular. Isso está desabilitado por padrão, a menos que seja definido de outra forma. O intervalo é medido em segundos. Um valor de 0 desativa o salvamento automático." - ) + MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, + "Arquivo de Trapaça" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, - "Se ativado, substitui os vínculos de entrada com as associações remapeadas definidas para o núcleo atual." - ) + MENU_ENUM_LABEL_VALUE_CHEAT_FILE, + "Arquivo de Trapaça" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_AUTODETECT_ENABLE, - "Habilita a detecção automática de entrada. Tentará configurar automaticamente joypads, estilo Plug-and-Play." - ) + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, + "Carregar Arquivo de Trapaça" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_INPUT_SWAP_OK_CANCEL, - "Troca de botões para OK/Cancelar. Desabilitado é o estilo de botão japonês, habilitada é oestilo ocidental." - ) + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD_APPEND, + "Carregar Arquivo de Trapaça (Anexado)" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Se desabilitado, o conteúdo continuará sendo executado em segundo plano quando o menu do RetroArch for alternado." - ) + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, + "Salvar Arquivo de Trapaça Como" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_DRIVER, - "Driver de vídeo para usar." - ) + MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, + "Estágios de Trapaça" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_DRIVER, - "Driver de áudio para usar." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, + "Descrição" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DRIVER, - "Driver de entrada para usar. Dependendo do driver de vídeo, pode forçar um driver de entrada diferente." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, + "Conquistas no Modo Hardcore" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, - "Driver do Joypad para usar." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_LEADERBOARDS_ENABLE, + "Tabelas de Classificação" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_DRIVER, - "Driver de reamostragem de áudio a ser utilizado." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_BADGES_ENABLE, + "Insígnias de Conquistas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_CAMERA_DRIVER, - "Driver de câmera a ser utilizado." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, + "Conquistas Bloqueadas:" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_LOCATION_DRIVER, - "Driver de localização a ser utilizado." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY, + "Bloqueada" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_DRIVER, - "Driver de menu a ser utilizado." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_SETTINGS, + "Retro Achievements" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_RECORD_DRIVER, - "Driver de gravação a ser utilizado." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, + "Testar Conquistas Não Oficiais" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_WIFI_DRIVER, - "Driver de WiFi a ser utilizado." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, + "Conquistas Desbloqueadas:" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, - "Filtra os arquivos em exibição no explorador de arquivos por extensões suportadas." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY, + "Desbloqueada" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_WALLPAPER, - "Seleciona uma imagem para definir como plano de fundo do menu." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, + "Hardcore" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER, - "Carrega dinamicamente um novo plano de fundo dependendo do contexto." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_VERBOSE_ENABLE, + "Modo Detalhado das Conquistas" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_DEVICE, - "Substitui o dispositivo de áudio padrão utilizado pelo driver de áudio. Isto depende do driver." - ) + MENU_ENUM_LABEL_VALUE_CHEEVOS_AUTO_SCREENSHOT, + "Captura de Conquistas Automática" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN, - "Plugin DSP de Áudio que processa o áudio antes de ser enviado para o driver." - ) + MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, + "Fechar Conteúdo" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_OUTPUT_RATE, - "Taxa de amostragem da saída de áudio." - ) + MENU_ENUM_LABEL_VALUE_CONFIG, + "Configuração" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, - "Opacidade de todos os elementos de interface da Transparência." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OVERLAY_SCALE, - "Escala de todos os elementos de interface da Transparência." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ENABLE, - "Habilita a Transparência." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OVERLAY_PRESET, - "Seleciona uma Transparência pelo navegador de arquivos." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, - "Endereço do hospedeiro a se conectar." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT, - "Porta do endereço de IP do hospedeiro. Pode ser uma porta TCP ou uma porta UDP." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, - "Senha para conectar ao hospedeiro de Netplay. Utilizado apenas no modo hospedeiro." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, - "Anunciar os jogos de Netplay publicamente. Se não for definido, os clientes deverão conectar manualmente em vez de usar o lobby público." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, - "Senha para conectar ao hospedeiro de Netplay apenas com privilégios de espectador. Utilizado apenas no modo hospedeiro." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_START_AS_SPECTATOR, - "Define se o Netplay deve iniciar em modo espectador." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_SLAVES, - "Define se conexões em modo escravo são permitidas. Clientes em modo escravo requerem muito pouco poder de processamento em ambos os lados, mas irão sofrer significamente da latência de rede." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_REQUIRE_SLAVES, - "Define se conexões que não estão em modo escravo são proibidas. Não recomendado, exceto para redes muito rápidas com máquinas muito lentas." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_STATELESS_MODE, - "Define se deve executar o Netplay em modo que não utilize Estados de Jogo. Se definido como verdadeiro, uma rede muito rápida é necessária, mas Rebobinagem não é permitido, então não haverá oscilação no Netplay." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_CHECK_FRAMES, - "Frequência em quadros no qual o Netplay verificará se o hospedeiro e o cliente estão sincronizados." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_NAT_TRAVERSAL, - "Ao hospedar uma partida, tente receber conexões da Internet pública usando UPnP ou tecnologias similares para escapar das redes locais." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, - "Habilitar interface de comando stdin." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_MOUSE_ENABLE, - "Habilitar controle por Mouse dentro do menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_POINTER_ENABLE, - "Habilitar controle por toque dentro do menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_THUMBNAILS, - "Tipo de miniatura a ser exibida." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, - "Tipo de miniatura para exibir à esquerda." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_XMB_VERTICAL_THUMBNAILS, - "Exibe a miniatura esquerda sob a direita, no lado direito da tela.") -MSG_HASH( - MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE, - "Exibir data e/ou hora atuais dentro do menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE, - "Exibir o nível de bateria atual dentro do menu." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NAVIGATION_WRAPAROUND, - "Voltar ao início ou final se o limite da lista for alcançado horizontalmente ou verticalmente." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, - "Habilita o Netplay no modo hospedeiro (servidor)." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_CLIENT, - "Habilita o Netplay no modo cliente.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_DISCONNECT, - "Desconecta de uma conexão de Netplay ativa.") -MSG_HASH(MENU_ENUM_SUBLABEL_SCAN_DIRECTORY, - "Analisa um diretório por arquivos compatíveis e os adiciona à coleção.") -MSG_HASH(MENU_ENUM_SUBLABEL_SCAN_FILE, - "Analisa um arquivo compatível e o adiciona à coleção.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SWAP_INTERVAL, - "Usa um intervalo de troca personalizado para V-Sync. Defina para reduzir efetivamente a taxa de atualização do monitor pela metade." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_SORT_SAVEFILES_ENABLE, - "Ordenar os Jogos-Salvos em pastas com o nome do núcleo utilizado." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE, - "Ordenar os Estados de Jogo em pastas com o nome do núcleo utilizado." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_REQUEST_DEVICE_I, - "Solicitar jogar com o dispositivo de entrada dado.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, - "URL para o diretório de atualização de núcleos no buildbot do Libreto.") -MSG_HASH(MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL, - "URL para o diretório de atualizações de recursos no buildbot do Libretro.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, - "Após o download, extrair automaticamente os arquivos contidos nos arquivos comprimidos baixados." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, - "Analisar por novas salas.") -MSG_HASH(MENU_ENUM_SUBLABEL_DELETE_ENTRY, - "Remover esta entrada da coleção.") -MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION, - "Visualizar mais informações sobre o conteúdo.") -MSG_HASH(MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES, - "Adicionar o item aos seus favoritos.") -MSG_HASH(MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES_PLAYLIST, - "Adicionar o item aos seus favoritos.") -MSG_HASH(MENU_ENUM_SUBLABEL_RUN, - "Iniciar o conteúdo.") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, - "Ajustar as definições do navegador de arquivos.") -MSG_HASH( - MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, - "Habilitar por padrão controles personalizados na inicialização." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, - "Habilitar por padrão configuração personalizada na inicialização." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, - "Habilitar por padrão opções de núcleo personalizadas na inicialização.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_ENABLE, - "Exibir o nome do núcleo atual dentro do menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_DATABASE_MANAGER, - "Visualizar bases de dados.") -MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_MANAGER, - "Visualizar pesquisas anteriores.") -MSG_HASH(MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, - "Captura uma imagem da tela.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Fecha o conteúdo atual. Alterações não salvas serão perdidas." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_STATE, - "Carregar um Estado de Jogo do compartimento selecionado atualmente.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_STATE, - "Salvar um Estado de Jogo no compartimento selecionado atualmente.") -MSG_HASH(MENU_ENUM_SUBLABEL_RESUME, - "Retomar a execução do conteúdo atual e sair do Menu Rápido.") -MSG_HASH(MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Retomar a execução do conteúdo atual e sair do Menu Rápido.") -MSG_HASH(MENU_ENUM_SUBLABEL_STATE_SLOT, - "Altera o compartimento do Estado de Jogo selecionado atualmente.") -MSG_HASH(MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE, - "Se um Estado de Jogo for carregado, o conteúdo voltará ao estado anterior ao carregamento.") -MSG_HASH(MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, - "Se o Estado de Jogo foi sobrescrito, ele voltará ao Estado de Jogo salvo anteriormente.") -MSG_HASH( - MENU_ENUM_SUBLABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, - "Serviço Retro Achievements. Para mais informações, visite http://retroachievements.org (em inglês)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, - "Gerenciar contas configuradas atualmente." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_META_REWIND, - "Gerenciar as configurações de Rebobinagem.") -MSG_HASH(MENU_ENUM_SUBLABEL_RESTART_CONTENT, - "Reinicia o conteúdo do começo.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, - "Salva um arquivo de redefinição de configuração que será aplicado a todo o conteúdo carregado por este núcleo. Terá prioridade sobre a configuração principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, - "Salva um arquivo de redefinição de configuração que será aplicado a todo o conteúdo carregado no mesmo diretório que o arquivo atual. Terá prioridade sobre a configuração principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, - "Salva um arquivo de redefinição de configuração que será aplicado apenas ao conteúdo atual. Terá prioridade sobre a configuração principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, - "Configurar códigos de Trapaça.") -MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_OPTIONS, - "Configurar Shader para realçar a aparência da imagem.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Alterar os controles para o conteúdo que está sendo executado.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Alterar as opções para o conteúdo que está sendo executado.") -MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, - "Exibir as configurações avançadas para usuários experientes (oculto por padrão).") -MSG_HASH(MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, - "Executar tarefas em linhas de processamento paralelas.") -MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, - "Permitir que o usuário possa remover itens das coleções.") -MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, - "Define o diretório de sistema. Os núcleos podem consultar este diretório para carregar arquivos de BIOS, configurações específicas do sistema, etc.") -MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, - "Define o diretório inicial do navegador de arquivos.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_DIR, - "Usualmente definido por desenvolvedores que agrupam aplicativos Libretro/RetroArch para apontar para os recursos." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPERS_DIRECTORY, - "Diretório para armazenar planos de fundo dinamicamente carregados pelo menu dependendo do contexto.") -MSG_HASH(MENU_ENUM_SUBLABEL_THUMBNAILS_DIRECTORY, - "Miniaturas auxiliares (arte da embalagem/imagens diversas e etc.) são armazenadas aqui." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, - "Define o diretório inicial para o navegador de configurações do menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, - "O número de quadros de latência de entrada para o Netplay utilizar para mascarar a latência da rede. Reduz a oscilação e torna o Netplay menos intensivo para a CPU, ao custo de atraso perceptível na entrada.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, - "O intervalo de quadros de latência de entrada que pode ser utilizado para mascarar a latência da rede. Reduz a oscilação e torna o Netplay menos intensivo para a CPU, ao custo de atraso imprevisível na entrada.") -MSG_HASH(MENU_ENUM_SUBLABEL_DISK_CYCLE_TRAY_STATUS, - "Alterna o disco atual. Se o disco estiver inserido, o mesmo será ejetado. Se o disco não estiver inserido, o mesmo será inserido.") -MSG_HASH(MENU_ENUM_SUBLABEL_DISK_INDEX, - "Mudar o índice do disco.") -MSG_HASH(MENU_ENUM_SUBLABEL_DISK_OPTIONS, - "Gerenciamento de imagem de disco.") -MSG_HASH(MENU_ENUM_SUBLABEL_DISK_IMAGE_APPEND, - "Selecione uma imagem de disco para inserir.") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_ENUM_THROTTLE_FRAMERATE, - "Certifica-se de que a taxa de quadros é controlada enquanto estiver dentro do menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_LAYOUT, - "Selecione um layout diferente para a interface XMB.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_THEME, - "Selecionar um tema diferente para os ícones. As alterações terão efeito após reiniciar o programa.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE, - "Habilitar as sombras para todos os ícones. Isto terá um pequeno impacto no desempenho.") -MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME, - "Selecionar um tema de gradiente de cor de plano de fundo diferente.") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY, - "Modificar a opacidade do plano de fundo.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_MENU_COLOR_THEME, - "Selecionar um tema de gradiente de cor de plano de fundo diferente.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, - "Selecionar um efeito de plano de fundo animado. Pode exigir mais processamento da GPU dependendo do efeito. Se o desempenho for insatisfatório, desligue este efeito ou reverta para um efeito mais simples.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_FONT, - "Selecionar uma fonte principal diferente para ser usada pelo menu.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_FAVORITES, - "Exibir a aba de favoritos dentro do menu principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, - "Exibir a aba de imagem dentro do menu principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, - "Exibir a aba de música dentro do menu principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, - "Exibir a aba de vídeo dentro do menu principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, - "Exibir a aba de Netplay dentro do menu principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS, - "Mostrar a aba de configurações dentro do menu principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_HISTORY, - "Mostrar a aba de histórico recente dentro do menu principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, - "Mostrar a aba de importação de conteúdo dentro do menu principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Exibir abas da lista de reprodução dentro do menu principal.") -MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, - "Exibir a tela inicial no menu. É automaticamente definido como falso após o programa iniciar pela primeira vez.") -MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, - "Modificar a opacidade do gráfico do cabeçalho.") -MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, - "Modificar a opacidade do gráfico do rodapé.") -MSG_HASH(MENU_ENUM_SUBLABEL_DPI_OVERRIDE_ENABLE, - "O menu normalmente se dimensiona dinamicamente. Se você desejar definir uma escala de tamanho específica em vez disto, habilite esta função.") -MSG_HASH(MENU_ENUM_SUBLABEL_DPI_OVERRIDE_VALUE, - "Definir o tamanho do dimensionamento personalizado aqui. OBS: Você deve habilitar a função 'Redefinição de DPI' para que este dimensionamento tenha efeito.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, - "Salvar todos os arquivos baixados neste diretório.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_REMAPPING_DIRECTORY, - "Salvar todos os controles remapeados neste diretório.") -MSG_HASH(MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, - "Diretório onde o programa busca por conteúdo/núcleos.") -MSG_HASH(MENU_ENUM_SUBLABEL_LIBRETRO_INFO_PATH, - "Os arquivos de informação do aplicativo/núcleo são armazenados aqui.") -MSG_HASH(MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, - "Se um Joypad estiver conectado, o mesmo será autoconfigurado se um arquivo de configuração correspondente estiver presente dento deste diretório.") -MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_DIRECTORY, - "Salvar todas as coleções neste diretório.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, - "Se for definido um diretório, o conteúdo que é temporariamente extraído (ex: dos arquivos) sera extraído para este diretório." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_DIRECTORY, - "As consultas salvas são armazenadas neste diretório.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, - "As bases de dados são armazenadas neste diretório." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, - "Esta localização é consultada por padrão quando a interface do menu tenta procurar por recursos carregáveis, etc." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_SAVEFILE_DIRECTORY, - "Salvar todos os Jogos-Salvos neste diretório. Se não for definido, tentaremos salvar dentro do diretório de trabalho do arquivo.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVESTATE_DIRECTORY, - "Salvar todos os Estados de Jogo neste diretório. Se não for definido, tentaremos salvar dentro do diretório de trabalho do arquivo.") -MSG_HASH(MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, - "Diretório para armazenar as capturas de tela.") -MSG_HASH(MENU_ENUM_SUBLABEL_OVERLAY_DIRECTORY, - "Define um diretório onde as Transparências são mantidas para fácil acesso.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_DATABASE_PATH, - "Os arquivos de Trapaça são mantidos aqui." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_FILTER_DIR, - "Diretório onde os arquivos de filtro DSP de áudio são mantidos." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FILTER_DIR, - "Diretório onde os arquivos de filtro de vídeo processado por CPU são mantidos." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_DIR, - "Define um diretório onde os arquivos de Shader de vídeo processado por GPU são mantidos para fácil acesso.") -MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_OUTPUT_DIRECTORY, - "As gravações serão armazenadas neste diretório.") -MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_CONFIG_DIRECTORY, - "As configurações de gravação serão mantidas aqui.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_PATH, - "Selecionar uma fonte diferente para as notificações na tela.") -MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_APPLY_CHANGES, - "As alterações das configurações de Shader terão efeito imediato. Use isto se você alterou a quantidade de estágios de Shader, filtros, escala FBO, etc.") -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_NUM_PASSES, - "Aumentar ou diminuir a quantidade de estágios do pipeline de Shader. Você pode adicionar um Shader separado para cada estágio do pipeline e configurar sua escala e filtro." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET, - "Carregar uma predefinição de Shader. O pipeline de Shader será definido automaticamente.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_AS, - "Salvar as definições de Shader atuais como uma nova predefinição de Shader.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, - "Salvar as definições de Shader atuais como a definição padrão para esta aplicação/núcleo.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_PARENT, - "Salve as configurações atuais do shader como as configurações padrão para todos os arquivos no diretório de conteúdo atual.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, - "Salvar as definições de Shader atuais como a definição padrão para o conteúdo.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, - "Modifica diretamente o Shader atual. As alterações não serão salvas no arquivo de predefinição.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PARAMETERS, - "Modifica a predefinição de Shader atualmente utilizada no menu.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, - "Aumentar ou diminuir a quantidade de Trapaças." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_CHEAT_APPLY_CHANGES, - "As alterações de Trapaça terão efeito imediato.") -MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, - "Carregar um arquivo de Trapaça." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CHEAT_FILE_SAVE_AS, - "Salvar as Trapaças atuais como um arquivo de Jogo-Salvo." - ) -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SETTINGS, - "Acessar rapidamente todas as configurações relevantes ao jogo.") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INFORMATION, - "Visualizar informações sobre a aplicação/núcleo.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO, - "Valor em ponto flutuante da proporção de tela (largura / altura), utilizado se Proporção de Tela estiver definido como 'Configuração'.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "Personalizar a altura da janela de exibição que é usada se a Proporção de Tela estiver definida como 'Personalizada'.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "Personalizar a largura da janela de exibição que é usada se a Proporção de Tela estiver definida como 'Personalizada'.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, - "Deslocamento personalizado no eixo-X da janela de exibição. Será ignorado se a 'Escala em Inteiros' estiver habilitada. Neste caso ela será centralizada automaticamente.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, - "Deslocamento personalizado no eixo-Y da janela de exibição. Será ignorado se a 'Escala em Inteiros' estiver habilitada. Neste caso ela será centralizada automaticamente.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Utilizar Servidor MITM") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, - "Encaminhar conexões do Netplay através de um servidor 'homem no meio' (MITM). Útil se o hospedeiro estiver atrás de um firewall ou tiver problemas de NAT/UPnP.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER, - "Localização do Servidor de Retransmissão") -MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_MITM_SERVER, - "Escolha um servidor de retransmissão específico para usar. Locais geograficamente mais próximos tendem a ter menor latência.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, - "Adicionar ao mixer") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_PLAY, - "Adicionar ao mixer e reproduzir") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION, - "Adicionar ao mixer") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY, - "Adicionar ao mixer e reproduzir") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, - "Filtrar por núcleo atual") -MSG_HASH( - MSG_AUDIO_MIXER_VOLUME, - "Volume global do mixer de áudio" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, - "Volume global do mixer de áudio (em dB). 0dB é o volume normal, e nenhum ganho será aplicado." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, - "Nível de Volume do Mixer de Áudio (dB)" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, - "Mixer de Áudio Mudo" - ) -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, - "Mixer de áudio mudo/não-mudo.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_ONLINE_UPDATER, - "Exibir Atualizador Online") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, - "Exibir/ocultar a opção 'Atualizador Online'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_VIEWS_SETTINGS, - "Visualizações") -MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_VIEWS_SETTINGS, - "Exibir elementos na tela de menu." - ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, - "Exibir Atualizador de Núcleos") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, - "Exibir/ocultar a opção de atualizar núcleos (e arquivos de informação de núcleo).") -MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, - "Preparando a busca de conteúdo...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, - "Remover núcleo") -MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, - "Remover este núcleo do disco.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, - "Opacidade do Framebuffer") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, - "Modificar a opacidade do framebuffer.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, - "Favoritos") -MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, - "Conteúdo adicionado aos 'Favoritos' vai aparecer aqui.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, - "Músicas") -MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, - "Músicas que foram reproduzidas aparecem aqui.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, - "Imagens") -MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, - "Imagens que foram exibidas aparecem aqui.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, - "Vídeos") -MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, - "Vídeos que foram reproduzidos aparecem aqui.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, - "Ícones do Menu") -MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, - "Habilitar/desabilitar os ícones exibidos do lado esquerdo dos itens de menu.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MAIN_MENU_ENABLE_SETTINGS, - "Habilitar aba de configurações") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS_PASSWORD, - "Definir senha para habilitar aba de configurações") -MSG_HASH(MSG_INPUT_ENABLE_SETTINGS_PASSWORD, - "Digite a senha") -MSG_HASH(MSG_INPUT_ENABLE_SETTINGS_PASSWORD_OK, - "Senha correta.") -MSG_HASH(MSG_INPUT_ENABLE_SETTINGS_PASSWORD_NOK, - "Senha incorreta.") -MSG_HASH(MENU_ENUM_SUBLABEL_XMB_MAIN_MENU_ENABLE_SETTINGS, - "Habilita a aba de configurações. É necessário reiniciar para que a aba apareça.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS_PASSWORD, - "O fornecimento de uma senha ao ocultar a aba de configurações permite restaurar mais tarde a partir do menu, indo para a aba Menu Principal, selecionando Habilitar aba configurações e inserindo a senha.") -MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, - "Permita que o usuário renomeie os itens nas coleções.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, - "Permitir renomear itens" ) -MSG_HASH(MENU_ENUM_SUBLABEL_RENAME_ENTRY, - "Renomear o título do item.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RENAME_ENTRY, - "Renomear") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CORE, - "Exibir 'Carregar Núcleo'") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CORE, - "Exibir/ocultar a opção 'Carregar Núcleo'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CONTENT, - "Exibir Carregar Conteúdo") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CONTENT, - "Exibir/ocultar a opção 'Carregar Conteúdo'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_INFORMATION, - "Exibir Informação") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_INFORMATION, - "Exibir/ocultar a opção 'Informação'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CONFIGURATIONS, - "Exibir Configurações") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CONFIGURATIONS, - "Exibir/ocultar a opção 'Configurações'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_HELP, - "Exibir Ajuda") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_HELP, - "Exibir/ocultar a opção 'Ajuda'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_QUIT_RETROARCH, - "Exibir Sair do RetroArch") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_QUIT_RETROARCH, - "Exibir/ocultar a opção 'Sair do RetroArch'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_REBOOT, - "Exibir Reiniciar") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_REBOOT, - "Exibir/ocultar a opção 'Reiniciar'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_SHUTDOWN, - "Exibir Desligar") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_SHUTDOWN, - "Exibir/ocultar a opção 'Desligar'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_VIEWS_SETTINGS, - "Menu Rápido") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_VIEWS_SETTINGS, - "Exibir ou ocultar elementos na tela de Menu Rápido.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_TAKE_SCREENSHOT, - "Exibir 'Captura de Tela'") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_TAKE_SCREENSHOT, - "Exibir/ocultar a opção 'Captura de Tela'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_LOAD_STATE, - "Exibir Salvar/Carregar Estado") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, - "Exibir/ocultar as opções para salvar/carregar estados.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, - "Exibir Desfazer Salvar/Carregar Estado") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, - "Exibir/ocultar as opções para abolir o salvar/carregar estado.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_FAVORITES, - "Exibir Adicionar aos Favoritos") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, - "Exibir/ocultar a opção 'Adicionar aos Favoritos'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_OPTIONS, - "Exibir Opções") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_OPTIONS, - "Exibir/ocultar a opção 'Opções'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CONTROLS, - "Exibir Controles") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CONTROLS, - "Exibir/ocultar a opção 'Controles'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CHEATS, - "Exibir Trapaças") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CHEATS, - "Exibir/ocultar a opção 'Trapaças'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SHADERS, - "Exibir 'Shaders'") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SHADERS, - "Exibir/ocultar a opção 'Shaders'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, - "Exibir Salvar Redefinição de Núcleo") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, - "Exibir/ocultar a opção 'Salvar Redefinição de Núcleo'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, - "Exibir Salvar Redefinição de Jogo") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, - "Exibir/ocultar a opção 'Salvar Redefinição de Jogo'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_INFORMATION, - "Exibir Informação") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_INFORMATION, - "Exibir/ocultar a opção 'Informação'.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_ENABLE, - "Ativar Notificação de Fundo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_RED, - "Notificação de Fundo em Cor Vermelha") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_GREEN, - "Notificação de Fundo em Cor Verde") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_BLUE, - "Notificação de Fundo em Cor Azul") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_OPACITY, - "Opacidade da Notificação de Fundo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_DISABLE_KIOSK_MODE, - "Desabilitar o Modo Quiosque") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_DISABLE_KIOSK_MODE, - "Desabilita o Modo Quiosque. É necessária uma reinicialização para que a mudança tenha total efeito.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_ENABLE_KIOSK_MODE, - "Habilitar o Modo Quiosque") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_ENABLE_KIOSK_MODE, - "Protege a configuração escondendo todas as configurações relacionadas à configuração.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_KIOSK_MODE_PASSWORD, - "Definir senha para desabilitar o Modo Quiosque") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_KIOSK_MODE_PASSWORD, - "Fornecer uma senha ao habilitar o Modo Quiosque tornando possível desabilitar mais tarde a partir do menu, indo para o Menu Principal, selecionando Desabilitar o Modo Quiosque e inserindo a senha.") -MSG_HASH(MSG_INPUT_KIOSK_MODE_PASSWORD, - "Digite a Senha") -MSG_HASH(MSG_INPUT_KIOSK_MODE_PASSWORD_OK, - "Senha correta.") -MSG_HASH(MSG_INPUT_KIOSK_MODE_PASSWORD_NOK, - "Senha incorreta.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_RED, - "Notificação em Cor Vermelha") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_GREEN, - "Notificação em Cor Verde") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_BLUE, - "Notificação em Cor Azul") -MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAMECOUNT_SHOW, - "Exibir contagem de quadros na tela FPS") -MSG_HASH(MSG_CONFIG_OVERRIDE_LOADED, - "Substituição de configuração carregada.") -MSG_HASH(MSG_GAME_REMAP_FILE_LOADED, - "Arquivo de remapeamento do jogo carregado.") -MSG_HASH(MSG_CORE_REMAP_FILE_LOADED, - "Arquivo de remapeamento principal carregado.") -MSG_HASH(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "O Adiantar Quadro foi desativado porque esse núcleo não suporta estados de jogo.") -MSG_HASH(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, - "Falha ao salvar o estado do jogo. O Adiantar Quadro foi desativado.") -MSG_HASH(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE, - "Falha ao carregar o estado do jogo. O Adiandar Quadro foi desativado.") -MSG_HASH(MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE, - "Falha ao criar uma segunda instância. O Adiantar Quadro agora usará apenas uma instância.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, - "Adicione automaticamente conteúdo à lista de reprodução") -MSG_HASH(MENU_ENUM_SUBLABEL_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, - "Verifica automaticamente o conteúdo carregado para que eles apareçam dentro das listas de reprodução.") -MSG_HASH(MSG_SCANNING_OF_FILE_FINISHED, - "Verificação do arquivo terminado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_OPACITY, - "Opacidade da Janela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_QUALITY, - "Qualidade da Reamostragem do Áudio") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_QUALITY, - "Abaixe esse valor para favorecer o desempenho/baixa latência em relação à qualidade de áudio, aumente se desejar melhor qualidade de áudio à custa do desempenho/baixa latência.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_WATCH_FOR_CHANGES, - "Ver arquivos de shader para mudanças") -MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, - "Aplicar automaticamente as alterações feitas nos arquivos de shader no disco.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SHOW_DECORATIONS, - "Exibir Decorações da Janela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_STATISTICS_SHOW, - "Exibir estatísticas") -MSG_HASH(MENU_ENUM_SUBLABEL_STATISTICS_SHOW, - "Mostrar estatísticas técnicas na tela.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_ENABLE, - "Ativar preenchimento de borda") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, - "Ativar espessura de preenchimento de borda") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, - "Ativar espessura de preenchimento do plano de fundo") -MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, - "Para monitores CRT de 15 kHz apenas. Tenta usar a resolução exata do núcleo/jogo e a taxa de atualização.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, - "Trocar para Resolução CRT") -MSG_HASH(MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, - "Quando Trocar para Resolução CRT está ativada, força a resolução horizontal ultrawide para minimizar a alternância de modo.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, - "Super Resolução CRT") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, - "Exibir Configurações de Rebobinagem") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, - "Exibir/ocultar as opções de Rebobinagem.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_LATENCY, - "Exibir/ocultar as opções de Latência.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_LATENCY, - "Exibir Configurações de Latência") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SHOW_OVERLAYS, - "Exibir/ocultar as opções de Sobreposição.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_OVERLAYS, - "Exibir Configurações de Sobreposição") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE_MENU, - "Ativar áudio de menu") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_ENABLE_MENU, - "Ativar ou desativar o som do menu.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_SETTINGS, - "Configurações do Mixer") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_SETTINGS, - "Visualizar e/ou modificar as configurações do mixer de áudio.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_INFO, - "Informação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_FILE, - "&Arquivo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_LOAD_CORE, - "&Carregar Núcleo...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_UNLOAD_CORE, - "&Descarregar Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_EXIT, - "Sai&r") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT, - "&Editar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT_SEARCH, - "&Pesquisar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW, - "&Visualizar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_CLOSED_DOCKS, - "Docas Fechadas") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS, - "&Opções...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS, - "Lembrar Posições da Doca:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY, - "Lembrar Geometria da Janela:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB, - "Lembrar a Última Aba do Navegador de Conteúdo:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME, - "Tema") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK, - "Escuro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM, - "Personalizado...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE, - "Opções") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOAD_CUSTOM_CORE, - "Carregar Núcleo Personalizado...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOAD_CORE, - "Carregar Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOADING_CORE, - "Carregando Núcleo...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_NAME, - "Nome") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CORE_VERSION, - "Versão") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_TAB_PLAYLISTS, - "Listas de Reprodução") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER, - "Navegador de Arquivos") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_TOP, - "Topo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_UP, - "Subir") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER, - "Navegador de Conteúdo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_BOXART, - "Arte da Capa") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_SCREENSHOT, - "Captura de Tela") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, - "Tela de Título") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, - "Todas as Listas de Reprodução") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CORE, - "Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CORE_INFO, - "Informação do Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CORE_SELECTION_ASK, - "") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_INFORMATION, - "Informação") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_WARNING, - "Advertência") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ERROR, - "Erro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESTART_TO_TAKE_EFFECT, - "Por favor, reinicie o programa para que as alterações entrem em vigor.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOG, - "Relatório") + MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, + "Carregar Configuração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, + "Configuração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, + "Salvar Configuração ao Sair" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST, + "Coleções" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, + "Base de Dados" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_DIR, + "Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, + "Tamanho da Lista de Histórico" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, + "Permitir a remoção de itens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, + "Menu Rápido" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, + "Recursos de Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, + "Downloads" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, + "Trapaças" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, + "Contadores do Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_ENABLE, + "Exibir nome do núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, + "Informação do Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, + "Autores" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, + "Categorias" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL, + "Rótulo do núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME, + "Nome do núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, + "Firmware(s)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, + "Licença(s)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, + "Permissões" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS, + "Extensões suportadas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_MANUFACTURER, + "Fabricante do sistema" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, + "Nome do sistema" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, + "Controles" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST, + "Carregar Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, + "Opções" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_SETTINGS, + "Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_SET_SUPPORTS_NO_CONTENT_ENABLE, + "Iniciar um Núcleo Automaticamente" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Extrair automaticamente o arquivo baixado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, + "URL de Núcleos do Buildbot" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST, + "Atualizador de Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, + "Atualizador" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CPU_ARCHITECTURE, + "Arquitetura da CPU:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CPU_CORES, + "Cores da CPU:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CURSOR_DIRECTORY, + "Cursor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CURSOR_MANAGER, + "Gerenciar Cursor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO, + "Proporção Personalizada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER, + "Gerenciar Base de Dados" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_SELECTION, + "Seleção de Base de Dados" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DELETE_ENTRY, + "Remover" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FAVORITES, + "Diretório Inicial" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, + "Diretório não encontrado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS, + "Diretório" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS, + "Condição da Bandeja do Ciclo de Disco" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, + "Anexar Imagem de Disco" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISK_INDEX, + "Índice de Disco" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, + "Controle de Disco" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DONT_CARE, + "Não importa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, + "Downloads" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE, + "Baixar Núcleo..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT, + "Download de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_ENABLE, + "Habilitar Redefinição de DPI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_VALUE, + "Redefinição de DPI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, + "Driver" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, + "Carregar Modelo no Desligamento do Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, + "Verificar por Firmware que Falta Antes de Carregar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, + "Plano de Fundo Dinâmico" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, + "Planos de Fundo Dinâmicos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, + "Habilitar Conquistas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, + "Cor do item de menu ao passar o cursor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, + "Cor normal do item de menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FALSE, + "Falso" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, + "Velocidade Máxima de Execução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, + "Favoritos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FPS_SHOW, + "Mostrar Taxa de Quadros" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, + "Controlar Velocidade Máxima de Execução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, + "Controle de Quadros" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, + "Contadores do Frontend" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, + "Carrega Automaticamente Opções de Núcleo Específicas do Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, + "Criar arquivo de opções do jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, + "Salvar arquivo de opções do jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP, + "Ajuda" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, + "Solução de Problemas de Áudio/Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, + "Alterando a Transparência de Gamepad Virtual" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, + "Controles Básicos de Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_LIST, + "Ajuda" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, + "Carregando Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, + "Procurando em Busca de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, + "O Que É Um Núcleo?" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, + "Habilitar Lista de Histórico" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HISTORY_TAB, + "Histórico" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, + "Menu Horizontal" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_IMAGES_TAB, + "Imagem" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INFORMATION, + "Informação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, + "Informação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, + "Tipo de Analógico Para Digital" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, + "Todos os Usuários Controlam o Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, + "Analógico Esquerdo X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, + "Analógico Esquerdo X- (esquerda)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, + "Analógico Esquerdo X+ (direita)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y, + "Analógico Esquerdo Y" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, + "Analógico Esquerdo Y- (cima)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, + "Analógico Esquerdo Y+ (baixo)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X, + "Analógico Direito X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, + "Analógico Direito X- (esquerda)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, + "Analógico Direito X+ (direita)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y, + "Analógico Direito Y" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, + "Analógico Direito Y- (cima)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, + "Analógico Direito Y+ (baixo)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, + "Gatinho da Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, + "Recarregar Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A, + "Aux A da Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B, + "Aux B da Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C, + "Aux C da Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START, + "Start da Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT, + "Select da Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP, + "D-pad Cima da Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN, + "D-pad Baixo da Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT, + "D-pad Esquerdo da Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, + "D-pad Direito da Pistola" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, + "Habilitar Autoconfiguração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, + "Zona Morta do Controle Analógico" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, + "Inverter Botões OK e Cancelar do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, + "Vincular Todos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, + "Vincular Todos pelo Padrão" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_BIND_TIMEOUT, + "Tempo Limite para Vincular" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_BIND_HOLD, + "Vincular (Manter Pressionado)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_HIDE_UNBOUND, + "Ocultar Descritores de Entrada do Núcleo Não Vinculados" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW, + "Exibir Rótulos do Descritor de Entrada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, + "Índice de Dispositivo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, + "Tipo de Dispositivo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, + "Índice de Mouse" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DRIVER, + "Driver de Entrada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + "Ciclo de Trabalho" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, + "Vínculos das Teclas de Atalho da Entrada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, + "Habilitar Mapeamento de Gamepad no Teclado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, + "Botão A (direita)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, + "Botão B (baixo)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, + "Direcional para baixo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, + "Botão L2 (gatilho)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, + "Botão L3 (polegar)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, + "Botão L (ombro)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, + "Direcional Esquerdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, + "Botão R2 (gatilho)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, + "Botão R3 (polegar)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, + "Botão R (ombro)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, + "Direcional Direito" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, + "Botão Select" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, + "Botão Start" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, + "Direcional para Cima" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, + "Botão X (topo)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, + "Botão Y (esquerda)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_KEY, + "(Tecla: %s)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_LEFT, + "Mouse 1" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_RIGHT, + "Mouse 2" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_MIDDLE, + "Mouse 3" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON4, + "Mouse 4" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON5, + "Mouse 5" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_UP, + "Roda do Mouse para Cima" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_DOWN, + "Roda do Mouse para Baixo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_UP, + "Roda do Mouse para Esquerda" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_DOWN, + "Roda do Mouse para Direita" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, + "Tipo de Mapeamento para Gamepad no Teclado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, + "Usuários Máximos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, + "Combinação do Gamepad para Alternar Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, + "Índice de Trapaça -" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, + "Índice de Trapaça +" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, + "Alternar Trapaça" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, + "Alternar ejeção de disco" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, + "Próximo disco" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, + "Disco anterior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, + "Habilitar teclas de atalho" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, + "Manter Avanço Rápido" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, + "Alternar Avanço Rápido" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, + "Avanço de Quadro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, + "Alternar tela cheia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, + "Alternar captura do Mouse" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, + "Alternar foco do jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, + "Alternar menu desktop" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, + "Carregar Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, + "Alternar menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, + "Alternar gravação de filme" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, + "Alternar áudio mudo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, + "Alternar modo jogador/espectador do Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, + "Alternar teclado virtual" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, + "Próxima Transparência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, + "Alternar pausa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, + "Sair do RetroArch" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, + "Reiniciar jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, + "Rebobinar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_DETAILS, + "Detalhes da Trapaça" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_SEARCH, + "Iniciar ou Continuar a Pesquisa de Trapaça" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, + "Salvar Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, + "Capturar tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, + "Próximo ahader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, + "Shader anterior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY, + "Manter câmera lenta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY, + "Alternar câmera lenta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, + "Compartimento do Estado de Jogo -" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, + "Compartimento do Estado de Jogo +" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, + "Volume -" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, + "Volume +" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, + "Mostrar Transparência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, + "Ocultar Transparência no Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Exibir Comandos Na Transparência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Porta de Escuta do Exibir Comandos " + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, + "Tipo de Comportamento da Chamada Seletiva" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, + "Mais cedo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_LATE, + "Mais tarde" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_NORMAL, + "Normal" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_PREFER_FRONT_TOUCH, + "Preferir Toque Frontal" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, + "Remapeamento de Entrada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, + "Habilitar Remapeamento de Vínculos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, + "Salvar Autoconfiguração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, + "Entrada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, + "Habilitar Teclado Pequeno" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_ENABLE, + "Habilitar Toque" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Habilitar Turbo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, + "Período do Turbo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, + "Vínculos de Entrada do Usuário %u" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LATENCY_SETTINGS, + "Latência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INTERNAL_STORAGE_STATUS, + "Condição do armazenamento interno" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, + "Autoconfiguração de Entrada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, + "Driver de Joypad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, + "Serviços" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_CHINESE_SIMPLIFIED, + "Chinês (Simplificado)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_CHINESE_TRADITIONAL, + "Chinês (Tradicional)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_DUTCH, + "Holandês" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_ENGLISH, + "Inglês" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_ESPERANTO, + "Esperanto" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_FRENCH, + "Francês" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_GERMAN, + "Alemão" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_ITALIAN, + "Italiano" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_JAPANESE, + "Japonês" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_KOREAN, + "Coreano" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_POLISH, + "Polonês" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_BRAZIL, + "Português (Brasil)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_PORTUGAL, + "Português (Portugal)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_RUSSIAN, + "Russo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_SPANISH, + "Espanhol" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE, + "Vietnamita" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LANG_ARABIC, + "Árabe" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, + "Analógico Esquerdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, + "Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, + "Informação do Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, + "Nível de Registro de Eventos do Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LINEAR, + "Linear" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, + "Carregar Arquivo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, + "Carregar Recente" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, + "Carregar Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOAD_STATE, + "Carregar Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, + "Permitir Localização" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER, + "Driver de Localização" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, + "Registro de Eventos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY, + "Verbosidade do Registro de Eventos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MAIN_MENU, + "Menu Principal" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MANAGEMENT, + "Configurações da Base de Dados" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, + "Tema de Cor do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE, + "Azul" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, + "Cinza Azulado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_DARK_BLUE, + "Azul Escuro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GREEN, + "Verde" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_NVIDIA_SHIELD, + "Shield" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_RED, + "Vermelho" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_YELLOW, + "Amarelo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, + "Opacidade do Rodapé" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, + "Opacidade do Cabeçalho" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_DRIVER, + "Driver de Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, + "Controlar Taxa de Quadros do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, + "Configurações" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, + "Filtro Linear de Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, + "Animação Horizontal" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, + "Aparência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, + "Plano de Fundo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, + "Opacidade do plano de fundo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MISSING, + "Faltando" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MORE, + "..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MOUSE_ENABLE, + "Suporte para Mouse" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MULTIMEDIA_SETTINGS, + "Multimídia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MUSIC_TAB, + "Música" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Filtrar Extensões Desconhecidas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, + "Navegação Retorna ao Início" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NEAREST, + "Mais Próximo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY, + "Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_SLAVES, + "Permitir Clientes em Modo Escravo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, + "Verificar Quadros do Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Quadros de Latência de Entrada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "Faixa de Quadros de Latência de Entrada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, + "Atraso de Quadros do Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, + "Desconectar do hospedeiro de Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, + "Habilitar Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, + "Conectar ao hospedeiro de Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, + "Iniciar hospedeiro de Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, + "Parar hospedeiro de Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, + "Endereço do Servidor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, + "Analisar a rede local" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, + "Habilitar Cliente Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, + "Usuário" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, + "Senha do Servidor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, + "Anunciar Netplay Publicamente" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_REQUEST_DEVICE_I, + "Solicitar Dispositivo %u" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_REQUIRE_SLAVES, + "Não Permitir Clientes em Modo Não Escravo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, + "Configurações do Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG, + "Compartilhamento de Entrada Analógica" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_MAX, + "Máximo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_AVERAGE, + "Médio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL, + "Compartilhamento de Entrada Digital" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_OR, + "Compartilhar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_XOR, + "Agarrar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_VOTE, + "Eleger" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NONE, + "Nenhum" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NO_PREFERENCE, + "Sem preferência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_START_AS_SPECTATOR, + "Modo Espectador do Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, + "Modo sem Estados de Jogo do Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, + "Senha Apenas Espectador do Servidor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, + "Habilitar Espectador do Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, + "Porta TCP do Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, + "Travessia de NAT do Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, + "Comandos de Rede" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, + "Porta de Comando de Rede" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION, + "Informação de Rede" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, + "Gamepad de Rede" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, + "Porta Base Remota de Rede" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, + "Rede" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO, + "Não" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NONE, + "Nenhum" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE, + "N/D" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY, + "Não há Conquistas para mostrar." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORE, + "Nenhum Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, + "Nenhum núcleo disponível" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, + "Não há informação de núcleo disponível." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, + "Não há opções de núcleo disponíveis." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, + "Não há itens para mostrar." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, + "Não há histórico disponível." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, + "Não há informação disponível." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_ITEMS, + "Sem itens." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, + "Nenhum hospedeiro de Netplay encontrado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, + "Nenhuma rede encontrada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, + "Não há contadores de desempenho." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, + "Não há listas de reprodução." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, + "Não há itens de lista de reprodução disponível." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, + "Nenhuma configuração encontrada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, + "Não há parâmetros de Shader." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OFF, + "DESLIGADO" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ON, + "LIGADO" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONLINE, + "Online" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, + "Atualizador Online" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, + "Exibição na Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, + "Transparência na Tela" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONSCREEN_OVERLAY_SETTINGS, + "Opções de controles de Notificações na Tela ou Molduras" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, + "Notificações na Tela" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONSCREEN_NOTIFICATIONS_SETTINGS, + "Ajustar Notificações na Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, + "Navegar no Arquivo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OPTIONAL, + "Opcional" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY, + "Transparência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, + "Carrega Automaticamente Transparência Favorita" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, + "Transparência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, + "Opacidade da Transparência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, + "Predefinição de Transparência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, + "Escala da Transparência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, + "Transparência na Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, + "Utilizar Modo PAL60" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, + "Diretório superior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, + "Pausar quando o menu for ativado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE, + "Não rodar em segundo plano" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE, + "Contadores de Desempenho" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB, + "Listas de Reprodução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, + "Lista de Reprodução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, + "Listas de Reprodução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, + "Suporte para Toque" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PORT, + "Porta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PRESENT, + "Presente" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS, + "Privacidade" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIDI_SETTINGS, + "MIDI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, + "Sair do RetroArch" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG, + "Analógico suportado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, + "Classificação BBFC" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CERO_RATING, + "Classificação CERO" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_COOP, + "Cooperativo suportado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CRC32, + "CRC32" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DESCRIPTION, + "Descrição" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER, + "Desenvolvedor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, + "Edição da Revista Edge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING, + "Classificação da Revista Edge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_REVIEW, + "Análise da Revista Edge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ELSPA_RATING, + "Classificação ELSPA" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, + "Hardware de Aprimoramento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ESRB_RATING, + "Classificação ESRB" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FAMITSU_MAGAZINE_RATING, + "Classificação da Revista Famitsu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE, + "Franquia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GENRE, + "Gênero" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MD5, + "MD5" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME, + "Nome" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ORIGIN, + "Origem" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PEGI_RATING, + "Classificação PEGI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, + "Editor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, + "Mês de Lançamento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, + "Ano de Lançamento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RUMBLE, + "Suporte para Vibração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SERIAL, + "Número de Série" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1, + "SHA1" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, + "Iniciar Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, + "Classificação TGDB" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REBOOT, + "Reiniciar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, + "Configuração de Gravação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, + "Saída de Gravação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS, + "Gravação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, + "Carregar Configuração de Gravação..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, + "Driver de Gravação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIDI_DRIVER, + "Driver MIDI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, + "Habilitar Gravação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_PATH, + "Salvar Saída de Gravação Como..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, + "Salvar Gravações no Diretório de Saída" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE, + "Arquivo de Remapeamento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, + "Carregar Arquivo de Remapeamento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, + "Salvar Arquivo de Remapeamento de Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CONTENT_DIR, + "Salvar Arquivo de Remapeamento de Jogo do Diretório de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, + "Salvar Arquivo de Remapeamento de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE, + "Excluir Arquivo de Remapeamento de Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME, + "Excluir Arquivo de Remapeamento de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CONTENT_DIR, + "Excluir Arquivo de Remapeamento de Jogo do Diretório de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REQUIRED, + "Obrigatório" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, + "Reiniciar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RESTART_RETROARCH, + "Reiniciar RetroArch" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RESUME, + "Retomar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, + "Retomar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, + "RetroKeyboard" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RETROPAD, + "RetroPad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, + "RetroPad com Analógico" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, + "Conquistas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_ENABLE, + "Habilitar Rebobinagem" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_AFTER_TOGGLE, + "Aplicar Após Alternar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_AFTER_LOAD, + "Aplicar Automaticamente Trapaças Durante o Carregamento do Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_GRANULARITY, + "Níveis da Rebobinamento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE, + "Tamanho do Buffer da Rebobinamento (MB)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE_STEP, + "Tamanho do Intervalo de Ajuste do Buffer (MB)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, + "Rebobinamento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SETTINGS, + "Configurações da Trapaça" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DETAILS_SETTINGS, + "Detalhes da Trapaça" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_SETTINGS, + "Iniciar ou Continuar a Pesquisa de Trapaça" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, + "Navegador de Arquivos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, + "Configuração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, + "Mostrar Tela Inicial" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, + "Analógico Direito" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, + "Adicionar aos Favoritos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES_PLAYLIST, + "Adicionar aos Favoritos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RESET_CORE_ASSOCIATION, + "Redefinir Associação do Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN, + "Executar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_MUSIC, + "Executar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, + "Habilitar SAMBA" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, + "Arquivo de Jogo-Salvo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, + "Índice Automático de Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, + "Carrega Automaticamente Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, + "Salvar Automaticamente Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, + "Arquivo de Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, + "Miniaturas do Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, + "Salvar Configuração Atual" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Salvar Redefinição de Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, + "Salvar Redefinições do Diretório de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, + "Salvar Redefinição de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, + "Salvar Nova Configuração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_STATE, + "Salvar Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, + "Salvando" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, + "Analisar Diretório" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCAN_FILE, + "Analisar Arquivo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, + "Captura de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, + "Resolução da Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SEARCH, + "Procurar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SECONDS, + "segundos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS, + "Configurações" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, + "Configurações" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER, + "Shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, + "Aplicar Alterações" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS, + "Shaders" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON, + "Faixa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON_SIMPLIFIED, + "Faixa (simplificada)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SIMPLE_SNOW, + "Neve Simples" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOW, + "Neve" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, + "Exibir Configurações Avançadas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, + "Exibir Arquivos e Pastas Ocultos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHUTDOWN, + "Desligar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, + "Taxa de Câmera Lenta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_ENABLED, + "Adiantar Quadro para Reduzir a Latência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_FRAMES, + "Número de Quadros para Adiantar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_SECONDARY_INSTANCE, + "O Adiantamento de Quadro Usará uma Segunda Instância" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_HIDE_WARNINGS, + "Ocultar Avisos do Adiantamento de Quadro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, + "Classificar Arquivos de Jogo-Salvo em Pastas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, + "Classificar Arquivos de Estado de Jogo em Pastas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE, + "Gravar Estados de Jogo no Diretório de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE, + "Gravar Jogos-Salvos no Diretório de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + "Arquivos de Sistema estão no Diretório de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + "Salvar Capturas de Tela no Diretório de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SSH_ENABLE, + "Habilitar SSH" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_START_CORE, + "Iniciar Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD, + "Iniciar RetroPad Remoto" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, + "Iniciar Processador de Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STATE_SLOT, + "Compartimento do Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STATUS, + "Condição" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE, + "Comandos stdin" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SUPPORTED_CORES, + "Núcleos Sugeridos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SUSPEND_SCREENSAVER_ENABLE, + "Desativar Protetor de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE, + "Habilitar Música em Segundo Plano do Sistema" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, + "Sistema/BIOS" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, + "Informação do Sistema" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT, + "Suporte a 7zip" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT, + "Suporte a ALSA" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_BUILD_DATE, + "Data de Compilação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CG_SUPPORT, + "Suporte a Cg" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COCOA_SUPPORT, + "Suporte a Cocoa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COMMAND_IFACE_SUPPORT, + "Suporte à Interface de Comando" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CORETEXT_SUPPORT, + "Suporte a CoreText" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CPU_FEATURES, + "Características de CPU" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_DPI, + "Métrica DPI da Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT, + "Métrica de Altura da Tela (mm)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH, + "Métrica de Largura da Tela (mm)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DSOUND_SUPPORT, + "Suporte a DirectSound" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT, + "Suporte a WASAPI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, + "Suporte à biblioteca dinâmica" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, + "Carregamento dinâmico em tempo de execução da biblioteca libretro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT, + "Suporte a EGL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT, + "Suporte a OpenGL/Direct3D render-to-texture (multi-pass shaders)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FFMPEG_SUPPORT, + "Suporte a FFmpeg" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FREETYPE_SUPPORT, + "Suporte a FreeType" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER, + "Identificador do Frontend" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_NAME, + "Nome do Frontend" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_OS, + "SO do Frontend" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GIT_VERSION, + "Versão Git" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GLSL_SUPPORT, + "Suporte a GLSL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_HLSL_SUPPORT, + "Suporte a HLSL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_JACK_SUPPORT, + "Suporte a JACK" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_KMS_SUPPORT, + "Suporte a KMS/EGL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LAKKA_VERSION, + "Versão Lakka" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBRETRODB_SUPPORT, + "Suporte a LibretroDB" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, + "Suporte a Libusb" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBXML2_SUPPORT, + "Suporte a libxml2 XML parsing" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, + "Suporte Netplay (ponto-a-ponto)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, + "Suporte à Interface de comando de rede" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_REMOTE_SUPPORT, + "Suporte a Gamepad de Rede" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT, + "Suporte a OpenAL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT, + "Suporte a OpenGL ES" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGL_SUPPORT, + "Suporte a OpenGL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENSL_SUPPORT, + "Suporte a OpenSL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENVG_SUPPORT, + "Suporte a OpenVG" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OSS_SUPPORT, + "Suporte a OSS" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OVERLAY_SUPPORT, + "Suporte à Transparência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE, + "Fonte de Energia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGED, + "Carregado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGING, + "Carregando" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_DISCHARGING, + "Descarregando" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE, + "Não há fonte" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, + "Suporte a PulseAudio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PYTHON_SUPPORT, + "Suporte a Python (suporte de script em Shaders)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RBMP_SUPPORT, + "Suporte a BMP (RBMP)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RETRORATING_LEVEL, + "Nível RetroRating" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RJPEG_SUPPORT, + "Suporte a JPEG (RJPEG)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ROARAUDIO_SUPPORT, + "Suporte a RoarAudio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RPNG_SUPPORT, + "Suporte a PNG (RPNG)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RSOUND_SUPPORT, + "Suporte a RSound" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RTGA_SUPPORT, + "Suporte a TGA (RTGA)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, + "Suporte a SDL2" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_IMAGE_SUPPORT, + "Suporte a imagem SDL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_SUPPORT, + "Suporte a SDL1.2" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SLANG_SUPPORT, + "Suporte a Slang" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_THREADING_SUPPORT, + "Suporte a Paralelismo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, + "Suporte a Udev" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, + "Suporte a Video4Linux2" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER, + "Driver de contexto de vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, + "Suporte a Vulkan" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_METAL_SUPPORT, + "Suporte a Metal" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT, + "Suporte a Wayland" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_X11_SUPPORT, + "Suporte a X11" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XAUDIO2_SUPPORT, + "Suporte a XAudio2" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT, + "Suporte a XVideo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT, + "Suporte a Zlib" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, + "Capturar tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, + "Paralelismo de tarefas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAILS, + "Miniaturas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS, + "Miniaturas à Esquerda" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_VERTICAL_THUMBNAILS, + "Disposição Vertical de Miniaturas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, + "Miniaturas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, + "Atualizador de Miniaturas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, + "Arte da Embalagem" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, + "Captura de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, + "Telas do Título" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, + "Exibir data e hora" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TITLE_COLOR, + "Cor do título do menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TRUE, + "Verdadeiro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, + "Habilitar Companheiro da Interface de Usuário" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, + "Companheiro da Interface de Usuário Roda na Inicialização" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UI_COMPANION_TOGGLE, + "Mostrar menu desktop na inicialização" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DESKTOP_MENU_ENABLE, + "Habilitar menu desktop (reiniciar)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, + "Barra de Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE, + "Incapaz de ler o arquivo comprimido." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, + "Desfazer Carregamento de Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, + "Desfazer Salvamento de Estado de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UNKNOWN, + "Desconhecido" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, + "Atualizador" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, + "Atualizar Recursos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, + "Atualizar Perfis de Autoconfiguração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, + "Atualizar Shaders Cg" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, + "Atualizar Trapaças" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, + "Atualizar Arquivos de Informação de Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, + "Atualizar Bases de Dados" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, + "Atualizar Shaders GLSL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, + "Atualizar Lakka" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, + "Atualizar Transparências" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATE_SLANG_SHADERS, + "Atualizar Shaders Slang" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USER, + "Usuário" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_KEYBOARD, + "Kbd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS, + "Interface de Usuário" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USER_LANGUAGE, + "Idioma" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USER_SETTINGS, + "Usuário" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Utilizar o Visualizador de Imagem Integrado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Utilizar o Reprodutor de Mídia Integrado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, + "Permitir rotação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO, + "Configurar Proporção de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, + "Proporção de Tela Automática" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, + "Proporção de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, + "Inserção de Quadro Opaco" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, + "Cortar Overscan (Recarregar)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, + "Desativar Composição da Área de Trabalho" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER, + "Driver de Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER, + "Filtro de Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, + "Filtro de Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, + "Filtro de tremulação de vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, + "Habilitar Notificações na Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, + "Fonte das Notificações na Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, + "Tamanho da Notificação na Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, + "Forçar Proporção de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE, + "Forçar Desativação de sRGB FBO" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, + "Atraso de Quadro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, + "Utilizar Modo de Tela Cheia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, + "Gama de Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, + "Usar Gravação da GPU" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, + "Habilitar Captura de Tela da GPU" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC, + "Sincronia Rígida de GPU" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC_FRAMES, + "Quadros de Sincronia Rígida de GPU" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Máximo de imagens na cadeia de troca" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, + "Posição X da Notificação na Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, + "Posição Y da Notificação na Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, + "Índice de Monitor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, + "Usar Gravação Pós-Filtro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, + "Taxa de Atualização Vertical" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, + "Taxa de Quadros Estimada da Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_POLLED, + "Definir Taxa de Atualização Reportada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ROTATION, + "Rotação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE, + "Escala em Janela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, + "Escala em Inteiros" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, + "Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, + "Shader de Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, + "Estágios de Shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, + "Pré-visualizar Parâmetros de Shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, + "Carregar Predefinição de Shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, + "Salvar Predefinição de Shader Como" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, + "Salvar Predefinição de Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT, + "Salvar Predefinição do Diretório de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, + "Salvar Predefinição de Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, + "Habilitar Contexto Compartilhado de Hardware" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, + "Filtragem Bilinear" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, + "Habilitar Filtro por Software" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, + "Intervalo de Troca da Sincronização Vertical (V-Sync)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_TAB, + "Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, + "Vídeo Paralelizado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, + "Reduzir Tremulação de Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, + "Altura Personalizada da Proporção de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, + "Largura Personalizada da Proporção de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, + "Posição X Personalizada da Proporção de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, + "Posição Y Personalizada da Proporção de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, + "Definir Largura de Tela do VI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, + "Sincronização Vertical (V-Sync)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, + "Modo Janela em Tela Cheia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, + "Largura da Janela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, + "Altura da Janela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_X, + "Largura em Tela Cheia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_Y, + "Altura em Tela Cheia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, + "Driver de Wi-Fi" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, + "Wi-Fi" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, + "Fator Alfa do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_RED, + "Cor Vermelha da Fonte do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_GREEN, + "Cor Verde da Fonte do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_BLUE, + "Cor Azul da Fonte do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_FONT, + "Fonte do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, + "Personalizado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, + "FlatUI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME, + "Monocromático" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME_INVERTED, + "Monocromático Invertido" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_SYSTEMATIC, + "Sistemático" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_NEOACTIVE, + "NeoActive" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_PIXEL, + "Pixel" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, + "RetroActive" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROSYSTEM, + "Retrosystem" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, + "Dot-Art" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, + "Tema de Cor do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_APPLE_GREEN, + "Verde Maçã" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK, + "Escuro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LIGHT, + "Claro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MORNING_BLUE, + "Azul da manhã" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK_PURPLE, + "Roxo Escuro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ELECTRIC_BLUE, + "Azul Elétrico" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GOLDEN, + "Dourado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LEGACY_RED, + "Vermelho Legado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDNIGHT_BLUE, + "Azul Meia-noite" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_PLAIN, + "Natural" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, + "Submarino" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, + "Vermelho Vulcânico" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, + "Pipeline do Shader de Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, + "Fator de Escala do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, + "Habilitar Sombras dos Ícones" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_HISTORY, + "Exibir Aba de Histórico" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, + "Exibir Aba de Importação de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, + "Exibir Abas de Lista de Reprodução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_FAVORITES, + "Exibir Aba de Favoritos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_IMAGES, + "Exibir Aba de Imagem" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_MUSIC, + "Exibir Aba de Música" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS, + "Exibir Aba de Configurações" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO, + "Exibir Aba de Vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, + "Exibir Aba de Netplay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_LAYOUT, + "Layout do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_THEME, + "Tema de Ícones do Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_YES, + "Sim" + ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, + "Predefinição de Shader" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, + "Habilitar ou desabilitar conquistas. Para mais informações, visite http://retroachievements.org" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, + "Habilitar ou desabilitar conquistas não oficiais e/ou recursos beta para fins de teste." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, + "Habilitar ou desabilitar Estado de Jogo, Trapaças, Rebobinamento, Avanço Rápido, Pausa e Câmera Lenta para todos os jogos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_LEADERBOARDS_ENABLE, + "Habilitar ou desabilitar tabelas de classificação no jogo. Não tem efeito se o modo Hardcore estiver desativado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_BADGES_ENABLE, + "Habilitar ou desabilitar a exibição de insígnia na Lista de Conquistas." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE, + "Habilitar ou desabilitar detalhes das conquistas na tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_AUTO_SCREENSHOT, + "Obter automaticamente uma captura de tela quando uma conquista é acionada." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, + "Alterar os drivers utilizados pelo sistema." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, + "Alterar as configurações de conquistas." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_SETTINGS, + "Alterar as configurações de núcleo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, + "Alterar as configurações de gravação." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, + "Alterar as configurações de Transparência e Transparência de teclado, e as configurações de notificação na tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, + "Alterar as configurações de Rebobinamento, Avanço Rápido e Câmera Lenta." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVING_SETTINGS, + "Alterar as configurações de salvamento." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, + "Alterar as configurações de registro de eventos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, + "Alterar as configurações da interface de usuário." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_USER_SETTINGS, + "Alterar as configurações de conta, nome de usuário e idioma." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, + "Alterar as configurações de privacidade." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIDI_SETTINGS, + "Alterar as Configurações de MIDI." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, + "Alterar os diretórios padrão onde os arquivos estão localizados." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, + "Alterar as configurações de lista de reprodução." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, + "Configurar as configurações de servidor e rede." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, + "Analisar conteúdo e adicionar na base de dados." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, + "Alterar as configurações de saída de áudio." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, + "Habilitar ou desabilitar o bluetooth." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, + "Salvar as alterações nos arquivos de configuração ao sair." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, + "Alterar as definições padrão para os arquivos de configuração." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, + "Gerenciar e criar arquivos de configuração." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CPU_CORES, + "Quantidade de Cores que a CPU possui." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FPS_SHOW, + "Exibir a taxa atual de quadros por segundo na tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, + "Ajustar configurações das teclas de atalho." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, + "Combinação de botões do Gamepad para alternar o menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_SETTINGS, + "Alterar as configurações de Joypad, teclado e Mouse." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, + "Configurar os controles para este usuário." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LATENCY_SETTINGS, + "Altere as configurações relacionadas a vídeo, áudio e latência dos comandos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOG_VERBOSITY, + "Habilitar ou desabilitar registro de eventos no terminal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY, + "Juntar-se ou hospedar uma sessão de Netplay." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, + "Procurar por e conectar aos hospedeiros de Netplay na rede local." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, + "Exibir informações de núcleo, rede e sistema." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONLINE_UPDATER, + "Baixar complementos, componentes e conteúdo para o RetroArch." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAMBA_ENABLE, + "Habilitar ou desabilitar compartilhamento de pastas na rede." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, + "Gerenciar serviços ao nível de sistema operacional." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, + "Exibir arquivos/diretórios ocultos no navegador de arquivos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SSH_ENABLE, + "Habilitar ou desabilitar acesso remoto à linha de comando." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, + "Prevenir que o protetor de tela do seu sistema seja ativado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, + "Definir o tamanho da janela em relação ao tamanho da janela de exibição do núcleo. Como alternativa, você pode definir uma largura e altura de janela abaixo para um tamanho de janela fixo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_USER_LANGUAGE, + "Definir o idioma da interface." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, + "Inserir um quadro opaco entre quadros. Útil para usuários com telas de 120Hz que desejam jogar conteúdos em 60Hz para eliminar efeito de fantasma." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, + "Reduz a latência ao custo de maior risco de engasgamento de vídeo. Adiciona um atraso após o V-Sync (em ms)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, + "Definir quantos quadros a CPU pode rodar à frente da GPU quando utilizado o recurso 'Sincronia Rígida de GPU'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Informar ao driver de vídeo para utilizar explicitamente um modo de buffer específico." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, + "Seleciona qual tela de exibição a ser usada." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, + "A taxa de atualização estimada da tela em Hz." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_POLLED, + "A taxa de atualização conforme relatada pelo driver de vídeo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, + "Alterar as configurações de saída de vídeo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_WIFI_SETTINGS, + "Analisar por redes sem fio e estabelecer uma conexão." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_HELP_LIST, + "Saiba mais sobre como o programa funciona." + ) +MSG_HASH( + MSG_ADDED_TO_FAVORITES, + "Adicionado aos favoritos" + ) +MSG_HASH( + MSG_RESET_CORE_ASSOCIATION, + "A associação do núcleo de entrada da lista de reprodução foi redefinida." + ) +MSG_HASH( + MSG_APPENDED_DISK, + "Disco anexado" + ) +MSG_HASH( + MSG_APPLICATION_DIR, + "Diretório do aplicativo" + ) +MSG_HASH( + MSG_APPLYING_CHEAT, + "Aplicando as alterações de Trapaças." + ) +MSG_HASH( + MSG_APPLYING_SHADER, + "Aplicando Shader" + ) +MSG_HASH( + MSG_AUDIO_MUTED, + "Áudio mudo." + ) +MSG_HASH( + MSG_AUDIO_UNMUTED, + "Áudio mudo desativado." + ) +MSG_HASH( + MSG_AUTOCONFIG_FILE_ERROR_SAVING, + "Erro em salvar o arquivo de autoconfiguração." + ) +MSG_HASH( + MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, + "Arquivo de autoconfiguração salvo com sucesso." + ) +MSG_HASH( + MSG_AUTOSAVE_FAILED, + "Não foi possível inicializar o salvamento automático." + ) +MSG_HASH( + MSG_AUTO_SAVE_STATE_TO, + "Salvar Automaticamente Estado de Jogo em" + ) +MSG_HASH( + MSG_BLOCKING_SRAM_OVERWRITE, + "Bloqueando Sobrescrita da SRAM" + ) +MSG_HASH( + MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, + "Trazendo a interface de comando na porta" + ) +MSG_HASH( + MSG_BYTES, + "bytes" + ) +MSG_HASH( + MSG_CANNOT_INFER_NEW_CONFIG_PATH, + "Não é possível inferir o novo caminho de configuração. Use a hora atual." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_ENABLE, + "Modo Hardcore Habilitado, Estados de Jogo e Rebobinamento estão desabilitados." + ) +MSG_HASH( + MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, + "Comparando com números mágicos conhecidos..." + ) +MSG_HASH( + MSG_COMPILED_AGAINST_API, + "Compilado contra a API" + ) +MSG_HASH( + MSG_CONFIG_DIRECTORY_NOT_SET, + "Diretório de configuração não definido. Não foi possível salvar a nova configuração." + ) +MSG_HASH( + MSG_CONNECTED_TO, + "Conectado a" + ) +MSG_HASH( + MSG_CONTENT_CRC32S_DIFFER, + "O CRC32 dos conteúdos difere. Não é possível utilizar jogos diferentes." + ) +MSG_HASH( + MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, + "Carregamento de conteúdo ignorado. A implementação irá carregar por conta própria." + ) +MSG_HASH( + MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, + "O núcleo não suporta Estados de Jogo." + ) +MSG_HASH( + MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, + "O arquivo de opções de núcleo foi criado com sucesso." + ) +MSG_HASH( + MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, + "Não foi possível encontrar nenhum driver seguinte" + ) +MSG_HASH( + MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, + "Não foi possível encontrar um sistema compatível." + ) +MSG_HASH( + MSG_COULD_NOT_FIND_VALID_DATA_TRACK, + "Não foi possível encontrar uma faixa de dados válida" + ) +MSG_HASH( + MSG_COULD_NOT_OPEN_DATA_TRACK, + "Não foi possível abrir a faixa de dados" + ) +MSG_HASH( + MSG_COULD_NOT_READ_CONTENT_FILE, + "Não foi possível ler o arquivo de conteúdo" + ) +MSG_HASH( + MSG_COULD_NOT_READ_MOVIE_HEADER, + "Não foi possível ler o cabeçalho do filme." + ) +MSG_HASH( + MSG_COULD_NOT_READ_STATE_FROM_MOVIE, + "Não foi possível ler o Estado de Jogo do filme." + ) +MSG_HASH( + MSG_CRC32_CHECKSUM_MISMATCH, + "Soma de verificação CRC32 incompatível entre o arquivo de conteúdo e a soma de verificação de conteúdo salva no cabeçalho do arquivo de reprodução. Reprodução altamente susceptível de dessincronizar na reprodução." + ) +MSG_HASH( + MSG_CUSTOM_TIMING_GIVEN, + "Tempo personalizado fornecido" + ) +MSG_HASH( + MSG_DECOMPRESSION_ALREADY_IN_PROGRESS, + "Descompressão já está em andamento." + ) +MSG_HASH( + MSG_DECOMPRESSION_FAILED, + "Descompressão falhou." + ) +MSG_HASH( + MSG_DETECTED_VIEWPORT_OF, + "Detectada janela de exibição de" + ) +MSG_HASH( + MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, + "Não encontrou uma modificação de conteúdo válido." + ) +MSG_HASH( + MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, + "Desconectar dispositivo de uma porta válida." + ) +MSG_HASH( + MSG_DISK_CLOSED, + "Fechado" + ) +MSG_HASH( + MSG_DISK_EJECTED, + "Ejetado" + ) +MSG_HASH( + MSG_DOWNLOADING, + "Baixando" + ) +MSG_HASH( + MSG_INDEX_FILE, + "index" + ) +MSG_HASH( + MSG_DOWNLOAD_FAILED, + "Download falhou" + ) +MSG_HASH( + MSG_ERROR, + "Erro" + ) +MSG_HASH( + MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, + "O núcleo libretro requer conteúdo, mas nada foi fornecido." + ) +MSG_HASH( + MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT, + "O núcleo libretro requer conteúdo especial, mas nenhum foi fornecido." + ) +MSG_HASH( + MSG_ERROR_PARSING_ARGUMENTS, + "Erro em analisar os argumentos." + ) +MSG_HASH( + MSG_ERROR_SAVING_CORE_OPTIONS_FILE, + "Erro em salvar o arquivo de opções de núcleo." + ) +MSG_HASH( + MSG_ERROR_SAVING_REMAP_FILE, + "Erro em salvar o arquivo de remapeamento." + ) +MSG_HASH( + MSG_ERROR_REMOVING_REMAP_FILE, + "Erro em remover o arquivo de remapeamento." + ) +MSG_HASH( + MSG_ERROR_SAVING_SHADER_PRESET, + "Erro em salvar a predefinição de Shader." + ) +MSG_HASH( + MSG_EXTERNAL_APPLICATION_DIR, + "Diretório de Aplicativo Externo" + ) +MSG_HASH( + MSG_EXTRACTING, + "Extraindo" + ) +MSG_HASH( + MSG_EXTRACTING_FILE, + "Extraindo arquivo" + ) +MSG_HASH( + MSG_FAILED_SAVING_CONFIG_TO, + "Falha em salvar a configuração em" + ) +MSG_HASH( + MSG_FAILED_TO, + "Falha em" + ) +MSG_HASH( + MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, + "Falha em aceitar o espectador ingresso." + ) +MSG_HASH( + MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, + "Falha em alocar memória para o conteúdo modificado..." + ) +MSG_HASH( + MSG_FAILED_TO_APPLY_SHADER, + "Falha em aplicar o Shader." + ) +MSG_HASH( + MSG_FAILED_TO_BIND_SOCKET, + "Falha em vincular o soquete." + ) +MSG_HASH( + MSG_FAILED_TO_CREATE_THE_DIRECTORY, + "Falha em criar o diretório." + ) +MSG_HASH( + MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, + "Falha em extrair o conteúdo do arquivo comprimido" + ) +MSG_HASH( + MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, + "Falha em obter o apelido do cliente." + ) +MSG_HASH( + MSG_FAILED_TO_LOAD, + "Falha em carregar" + ) +MSG_HASH( + MSG_FAILED_TO_LOAD_CONTENT, + "Falha em carregar o conteúdo" + ) +MSG_HASH( + MSG_FAILED_TO_LOAD_MOVIE_FILE, + "Falha em carregar o arquivo de filme" + ) +MSG_HASH( + MSG_FAILED_TO_LOAD_OVERLAY, + "Falha em carregar a Transparência." + ) +MSG_HASH( + MSG_FAILED_TO_LOAD_STATE, + "Falha em carregar o Estado de Jogo de" + ) +MSG_HASH( + MSG_FAILED_TO_OPEN_LIBRETRO_CORE, + "Falha em abrir o núcleo Libretro" + ) +MSG_HASH( + MSG_FAILED_TO_PATCH, + "Falha em executar a modificação" + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT, + "Falha em receber o cabeçalho do cliente." + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_NICKNAME, + "Falha em receber o apelido." + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST, + "Falha em receber o apelido do hospedeiro." + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_NICKNAME_SIZE_FROM_HOST, + "Falha em receber o tamanho do apelido do hospedeiro." + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST, + "Falha em receber os dados SRAM do hospedeiro." + ) +MSG_HASH( + MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY, + "Falha em remover o disco da bandeja." + ) +MSG_HASH( + MSG_FAILED_TO_REMOVE_TEMPORARY_FILE, + "Falha em remover o arquivo temporário" + ) +MSG_HASH( + MSG_FAILED_TO_SAVE_SRAM, + "Falha em salvar SRAM" + ) +MSG_HASH( + MSG_FAILED_TO_SAVE_STATE_TO, + "Falha em salvar o Estado de Jogo em" + ) +MSG_HASH( + MSG_FAILED_TO_SEND_NICKNAME, + "Falha em enviar o apelido." + ) +MSG_HASH( + MSG_FAILED_TO_SEND_NICKNAME_SIZE, + "Falha em enviar o tamanho do apelido." + ) +MSG_HASH( + MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT, + "Falha em enviar o apelido para o cliente." + ) +MSG_HASH( + MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, + "Falha em enviar o apelido para o hospedeiro." + ) +MSG_HASH( + MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, + "Falha em enviar os dados SRAM para o cliente." + ) +MSG_HASH( + MSG_FAILED_TO_START_AUDIO_DRIVER, + "Falha em iniciar o driver de áudio. Prosseguindo sem áudio." + ) +MSG_HASH( + MSG_FAILED_TO_START_MOVIE_RECORD, + "Falha em iniciar a gravação do filme." + ) +MSG_HASH( + MSG_FAILED_TO_START_RECORDING, + "Falha em iniciar a gravação." + ) +MSG_HASH( + MSG_FAILED_TO_TAKE_SCREENSHOT, + "Falha em obter uma captura de tela." + ) +MSG_HASH( + MSG_FAILED_TO_UNDO_LOAD_STATE, + "Falha em desfazer o carregamento de Estado de Jogo." + ) +MSG_HASH( + MSG_FAILED_TO_UNDO_SAVE_STATE, + "Falha em desfazer o salvamento de Estado de Jogo." + ) +MSG_HASH( + MSG_FAILED_TO_UNMUTE_AUDIO, + "Falha em desativar o áudio mudo." + ) +MSG_HASH( + MSG_FATAL_ERROR_RECEIVED_IN, + "Erro fatal recebido em" + ) +MSG_HASH( + MSG_FILE_NOT_FOUND, + "Arquivo não encontrado" + ) +MSG_HASH( + MSG_FOUND_AUTO_SAVESTATE_IN, + "Estado de Jogo automático encontrado em" + ) +MSG_HASH( + MSG_FOUND_DISK_LABEL, + "Rótulo de disco encontrado" + ) +MSG_HASH( + MSG_FOUND_FIRST_DATA_TRACK_ON_FILE, + "Encontrada primeira faixa de dados no arquivo" + ) +MSG_HASH( + MSG_FOUND_LAST_STATE_SLOT, + "Encontrada último compartimento de Estado de Jogo" + ) +MSG_HASH( + MSG_FOUND_SHADER, + "Shader encontrado" + ) +MSG_HASH( + MSG_FRAMES, + "Quadros" + ) +MSG_HASH( + MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT, + "Opções por Jogo: Opções de núcleo específicas do jogo encontradas em" + ) +MSG_HASH( + MSG_GOT_INVALID_DISK_INDEX, + "Índice de disco inválido obtido" + ) +MSG_HASH( + MSG_GRAB_MOUSE_STATE, + "Capturar estado do Mouse" + ) +MSG_HASH( + MSG_GAME_FOCUS_ON, + "Foco do jogo ligado" + ) +MSG_HASH( + MSG_GAME_FOCUS_OFF, + "Foco do jogo desligado" + ) +MSG_HASH( + MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, + "O núcleo libretro é renderizado por hardware. Deve usar a gravação pós-Shader também." + ) +MSG_HASH( + MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, + "A soma de verificação inflada não corresponde ao CRC32." + ) +MSG_HASH( + MSG_INPUT_CHEAT, + "Entrada de Trapaça" + ) +MSG_HASH( + MSG_INPUT_CHEAT_FILENAME, + "Nome do Arquivo de Trapaça" + ) +MSG_HASH( + MSG_INPUT_PRESET_FILENAME, + "Nome de Arquivo de Predefinição" + ) +MSG_HASH( + MSG_INPUT_RENAME_ENTRY, + "Renomear Título" + ) +MSG_HASH( + MSG_INTERFACE, + "Interface" + ) +MSG_HASH( + MSG_INTERNAL_STORAGE, + "Armazenamento Interno" + ) +MSG_HASH( + MSG_REMOVABLE_STORAGE, + "Armazenamento Removível" + ) +MSG_HASH( + MSG_INVALID_NICKNAME_SIZE, + "Tamanho de apelido inválido." + ) +MSG_HASH( + MSG_IN_BYTES, + "em bytes" + ) +MSG_HASH( + MSG_IN_GIGABYTES, + "em gigabytes" + ) +MSG_HASH( + MSG_IN_MEGABYTES, + "em megabytes" + ) +MSG_HASH( + MSG_LIBRETRO_ABI_BREAK, + "foi compilado contra uma versão diferente do libretro do que esta." + ) +MSG_HASH( + MSG_LIBRETRO_FRONTEND, + "Frontend para Libretro" + ) +MSG_HASH( + MSG_LOADED_STATE_FROM_SLOT, + "Estado de Jogo carregado do compartimento #%d." + ) +MSG_HASH( + MSG_LOADED_STATE_FROM_SLOT_AUTO, + "Estado de Jogo carregado do compartimento #-1 (automático)." + ) +MSG_HASH( + MSG_LOADING, + "Carregando" + ) +MSG_HASH( + MSG_FIRMWARE, + "Um ou mais arquivos de firmware estão faltando" + ) +MSG_HASH( + MSG_LOADING_CONTENT_FILE, + "Carregando arquivo de conteúdo" + ) +MSG_HASH( + MSG_LOADING_HISTORY_FILE, + "Carregando arquivo de histórico" + ) +MSG_HASH( + MSG_LOADING_STATE, + "Carregando Estado de Jogo" + ) +MSG_HASH( + MSG_MEMORY, + "Memória" + ) +MSG_HASH( + MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, + "O arquivo de filme não é um arquivo BSV1 válido." + ) +MSG_HASH( + MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, + "O formato de filme parece ter uma versão de serializador diferente. Provavelmente irá falhar." + ) +MSG_HASH( + MSG_MOVIE_PLAYBACK_ENDED, + "Reprodução de filme terminou." + ) +MSG_HASH( + MSG_MOVIE_RECORD_STOPPED, + "Parando a gravação de filme." + ) +MSG_HASH( + MSG_NETPLAY_FAILED, + "Falha em inicializar o Netplay." + ) +MSG_HASH( + MSG_NO_CONTENT_STARTING_DUMMY_CORE, + "Sem conteúdo, iniciando um núcleo modelo." + ) +MSG_HASH( + MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, + "Nenhum Estado de Jogo foi sobrescrito até o momento." + ) +MSG_HASH( + MSG_NO_STATE_HAS_BEEN_LOADED_YET, + "Nenhum Estado de Jogo foi carregado até o momento." + ) +MSG_HASH( + MSG_OVERRIDES_ERROR_SAVING, + "Erro em salvar as redefinições." + ) +MSG_HASH( + MSG_OVERRIDES_SAVED_SUCCESSFULLY, + "Redefinições salvas com sucesso." + ) +MSG_HASH( + MSG_PAUSED, + "Pausado." + ) +MSG_HASH( + MSG_PROGRAM, + "RetroArch" + ) +MSG_HASH( + MSG_READING_FIRST_DATA_TRACK, + "Lendo a primeira faixa de dados..." + ) +MSG_HASH( + MSG_RECEIVED, + "recebido" + ) +MSG_HASH( + MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, + "A gravação terminou devido ao redimensionamento." + ) +MSG_HASH( + MSG_RECORDING_TO, + "Gravando em" + ) +MSG_HASH( + MSG_REDIRECTING_CHEATFILE_TO, + "Redirecionando o arquivo de Trapaça em" + ) +MSG_HASH( + MSG_REDIRECTING_SAVEFILE_TO, + "Redirecionando o Jogo-Salvo em" + ) +MSG_HASH( + MSG_REDIRECTING_SAVESTATE_TO, + "Redirecionando o Estado de Jogo em" + ) +MSG_HASH( + MSG_REMAP_FILE_SAVED_SUCCESSFULLY, + "Arquivo de remapeamento salvo com sucesso." + ) +MSG_HASH( + MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, + "Arquivo de remapeamento salvo com sucesso." + ) +MSG_HASH( + MSG_REMOVED_DISK_FROM_TRAY, + "Disco removido da bandeja." + ) +MSG_HASH( + MSG_REMOVING_TEMPORARY_CONTENT_FILE, + "Removendo arquivo de conteúdo temporário" + ) +MSG_HASH( + MSG_RESET, + "Reinicializar" + ) +MSG_HASH( + MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT, + "Reiniciando a gravação devido ao reinício do driver." + ) +MSG_HASH( + MSG_RESTORED_OLD_SAVE_STATE, + "Estado de Jogo antigo restaurado." + ) +MSG_HASH( + MSG_RESTORING_DEFAULT_SHADER_PRESET_TO, + "Shaders: restaurando predefinição padrão de Shader em" + ) +MSG_HASH( + MSG_REVERTING_SAVEFILE_DIRECTORY_TO, + "Revertendo diretório de Jogo-Salvo em" + ) +MSG_HASH( + MSG_REVERTING_SAVESTATE_DIRECTORY_TO, + "Revertendo diretório de Estado de Jogo em" + ) +MSG_HASH( + MSG_REWINDING, + "Voltando atrás." + ) +MSG_HASH( + MSG_REWIND_INIT, + "Inicializando o buffer de Rebobinamento com tamanho" + ) +MSG_HASH( + MSG_REWIND_INIT_FAILED, + "Falha em inicializar o buffer de Rebobinamento. O rebobinamento será desativado." + ) +MSG_HASH( + MSG_REWIND_INIT_FAILED_THREADED_AUDIO, + "Esta implementação usa áudio paralelizado. Não é possível utilizar o rebobinamento." + ) +MSG_HASH( + MSG_REWIND_REACHED_END, + "Final do buffer de rebobinamento atingido." + ) +MSG_HASH( + MSG_SAVED_NEW_CONFIG_TO, + "Nova configuração salva em" + ) +MSG_HASH( + MSG_SAVED_STATE_TO_SLOT, + "Estado de Jogo salvo no compartimento #%d." + ) +MSG_HASH( + MSG_SAVED_STATE_TO_SLOT_AUTO, + "Estado de Jogo salvo no compartimento #-1 (automático)." + ) +MSG_HASH( + MSG_SAVED_SUCCESSFULLY_TO, + "Salvo com sucesso em" + ) +MSG_HASH( + MSG_SAVING_RAM_TYPE, + "Salvando Tipo de RAM" + ) +MSG_HASH( + MSG_SAVING_STATE, + "Salvando Estado de Jogo" + ) +MSG_HASH( + MSG_SCANNING, + "Analisando" + ) +MSG_HASH( + MSG_SCANNING_OF_DIRECTORY_FINISHED, + "Análise de diretório terminada" + ) +MSG_HASH( + MSG_SENDING_COMMAND, + "Enviando comando" + ) +MSG_HASH( + MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED, + "Várias modificações de conteúdo estão explicitamente definidas, ignorando todas..." + ) +MSG_HASH( + MSG_SHADER, + "Shader" + ) +MSG_HASH( + MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, + "Predefinição de Shader salva com sucesso." + ) +MSG_HASH( + MSG_SKIPPING_SRAM_LOAD, + "Ignorando carregamento da SRAM." + ) +MSG_HASH( + MSG_SLOW_MOTION, + "Câmera Lenta." + ) +MSG_HASH( + MSG_FAST_FORWARD, + "Avanço rápido." + ) +MSG_HASH( + MSG_SLOW_MOTION_REWIND, + "Rebobinamento em Câmera Lenta." + ) +MSG_HASH( + MSG_SRAM_WILL_NOT_BE_SAVED, + "SRAM não será salva." + ) +MSG_HASH( + MSG_STARTING_MOVIE_PLAYBACK, + "Iniciando reprodução de filme." + ) +MSG_HASH( + MSG_STARTING_MOVIE_RECORD_TO, + "Iniciando a gravação de filme em" + ) +MSG_HASH( + MSG_STATE_SIZE, + "Tamanho do Estado de Jogo" + ) +MSG_HASH( + MSG_STATE_SLOT, + "Compartimento do Estado de Jogo" + ) +MSG_HASH( + MSG_TAKING_SCREENSHOT, + "Fazendo captura de tela" + ) +MSG_HASH( + MSG_TO, + "em" + ) +MSG_HASH( + MSG_UNDID_LOAD_STATE, + "Desfez o carregamento de Estado de Jogo." + ) +MSG_HASH( + MSG_UNDOING_SAVE_STATE, + "Desfazendo o salvamento de Estado de Jogo" + ) +MSG_HASH( + MSG_UNKNOWN, + "Desconhecido" + ) +MSG_HASH( + MSG_UNPAUSED, + "Retomando." + ) +MSG_HASH( + MSG_UNRECOGNIZED_COMMAND, + "Comando não reconhecido" + ) +MSG_HASH( + MSG_USING_CORE_NAME_FOR_NEW_CONFIG, + "Usando o nome do núcleo para uma nova configuração." + ) +MSG_HASH( + MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, + "Usando o núcleo libretro modelo. Pulando a gravação." + ) +MSG_HASH( + MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, + "Conecte o dispositivo a partir de uma porta válida." + ) +MSG_HASH( + MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, + "Desconectando o dispositivo da porta" + ) +MSG_HASH( + MSG_VALUE_REBOOTING, + "Reinicializando..." + ) +MSG_HASH( + MSG_VALUE_SHUTTING_DOWN, + "Desligando..." + ) +MSG_HASH( + MSG_VERSION_OF_LIBRETRO_API, + "Versão da API libretro" + ) +MSG_HASH( + MSG_VIEWPORT_SIZE_CALCULATION_FAILED, + "Falha no cálculo de tamanho da janela de exibição! Prosseguindo usando dados brutos. Isto provavelmente não funcionará corretamente..." + ) +MSG_HASH( + MSG_VIRTUAL_DISK_TRAY, + "bandeja de disco virtual." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_LATENCY, + "Latência de áudio desejada em milissegundos. Pode não ser honrado se o driver de áudio não puder prover a latência desejada." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MUTE, + "Áudio mudo/não-mudo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, + "Ajuda a suavizar as imperfeições na regulagem ao sincronizar áudio e vídeo. Esteja ciente que se desativado, será quase impossível de se obter a sincronia adequada." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CAMERA_ALLOW, + "Permitir ou não o acesso à câmera pelos núcleos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOCATION_ALLOW, + "Permitir ou não o acesso ao serviço de localização pelos núcleos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, + "Número máximo de usuários suportados pelo RetroArch." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, + "Influencia como a chamada seletiva de entrada é feita dentro do RetroArch. Definindo com 'Cedo' ou 'Tarde' pode resultar em menos latência, dependendo da sua configuração." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, + "Permitir a qualquer usuário controlar o menu. Se desabilitado, apenas o Usuário 1 poderá controlar o menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_VOLUME, + "Volume do áudio (em dB). 0dB é o volume normal, e nenhum ganho é aplicado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_EXCLUSIVE_MODE, + "Permitir ao driver WASAPI obter controle exclusivo do dispositivo de áudio. Se desativado, o modo compartilhado será utilizado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_FLOAT_FORMAT, + "Utilizar formato de ponto flutuante para o driver WASAPI, se suportado pelo dispositivo de áudio." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH, + "O tamanho (em quadros) do buffer intermediário quando o driver WASAPI estiver em modo compartilhado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_SYNC, + "Sincroniza o áudio. Recomendado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, + "Até que ponto um eixo deve ser movido para resultar em um botão pressionado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, + "Quantidade de segundos para aguardar até proceder para o próximo vínculo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_BIND_HOLD, + "Quantidade de segundos para manter uma entrada para vinculá-la." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, + "Descreve o período quando os botões com turbo habilitado são alternados. Os números são descritos em quadros." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, + "Descreve quão longo deve ser o período de um botão com turbo habilitado. Os números são descritos como quadros." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VSYNC, + "Sincroniza o vídeo de saída da placa gráfica com a taxa de atualização da tela. Recomendado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, + "Permite que os núcleos definam a rotação. Quando desabilitado, as requisições de rotação são ignoradas. Útil para configurações onde se rotaciona manualmente a tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN, + "Alguns núcleos podem ter um recurso de desligamento. Se habilitado, impedirá que o núcleo feche o RetroArch. Em vez disto, carrega um núcleo modelo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, + "Verifica se todos os firmwares necessários estão presentes antes de tentar carregar conteúdo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, + "Taxa de atualização vertical da sua tela. Utilizado para calcular uma taxa de saída de áudio adequada. OBS: Isto será ignorado se a função 'Vídeo Paralelizado' estiver habilitada." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_ENABLE, + "Habilita a saída de áudio." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, + "Mudança máxima na taxa de entrada de áudio. Se aumentado habilita grandes mudanças na regulagem ao custo de imprecisão no timbre do som (ex: rodando núcleos PAL em modo NTSC)." + ) +MSG_HASH( + MSG_FAILED, + "falhou" + ) +MSG_HASH( + MSG_SUCCEEDED, + "teve êxito" + ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED, + "não configurado" + ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "não configurado, usando reserva" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, + "Lista de Cursores da Base de Dados" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DEVELOPER, + "Base de Dados - Filtro : Desenvolvedor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PUBLISHER, + "Base de Dados - Filtro : Publicador" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISABLED, + "Desabilitado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ENABLED, + "Habilitado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_PATH, + "Caminho do Histórico de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ORIGIN, + "Base de Dados - Filtro : Origem" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_FRANCHISE, + "Base de Dados - Filtro : Franquia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ESRB_RATING, + "Base de Dados - Filtro : Classificação ESRB" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ELSPA_RATING, + "Base de Dados - Filtro : Classificação ELSPA" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PEGI_RATING, + "Base de Dados - Filtro : Classificação PEGI" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_CERO_RATING, + "Base de Dados - Filtro : Classificação CERO" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_BBFC_RATING, + "Base de Dados - Filtro : Classificação BBFC" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_MAX_USERS, + "Base de Dados - Filtro : Usuários máximos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_MONTH, + "Base de Dados - Filtro : Data de Lançamento Por Mês" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_YEAR, + "Base de Dados - Filtro : Data de Lançamento Por Ano" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, + "Base de Dados - Filtro : Edição da Revista Edge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, + "Base de Dados - Filtro : Classificação da Revista Edge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, + "Informações da Base de Dados" + ) +MSG_HASH( + MSG_WIFI_SCAN_COMPLETE, + "Análise de Wi-Fi completa." + ) +MSG_HASH( + MSG_SCANNING_WIRELESS_NETWORKS, + "Analisando redes sem fio..." + ) +MSG_HASH( + MSG_NETPLAY_LAN_SCAN_COMPLETE, + "Análise de Netplay completa." + ) +MSG_HASH( + MSG_NETPLAY_LAN_SCANNING, + "Analisando por hospedeiros de Netplay..." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, + "Pausar o jogo quando a janela do RetroArch não estiver ativa." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, + "Habilitar ou desabilitar composição (Somente no Windows)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, + "Habilitar ou desabilitar a lista de reprodução recente para jogos, imagens, música e vídeos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, + "Limita o número de itens da lista de reprodução recente para jogos, imagens, música e vídeos." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, + "Controles de Menu Unificados" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, + "Utilizar os mesmos controles para o menu e jogo. Aplica-se ao teclado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, + "Exibir mensagens na tela." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, + "Habilitar Remoto do Usuário %d" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, + "Exibir nível de bateria" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SELECT_FILE, + "Selecionar Arquivo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SELECT_FROM_COLLECTION, + "Selecionar de Coleção" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FILTER, + "Filtro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCALE, + "Escala" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, + "O Netplay irá iniciar quando o conteúdo for carregado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, + "Não foi possível encontrar um núcleo adequado ou arquivo de conteúdo, carregue manualmente." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, + "Navegar pela URL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BROWSE_URL, + "Caminho da URL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BROWSE_START, + "Iniciar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, + "Bokeh" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOWFLAKE, + "Floco de neve" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, + "Atualizar Lista de Salas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, + "Apelido: %s" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, + "Apelido (lan): %s" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, + "Conteúdo compatível encontrado" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, + "Corta alguns pixels ao redor das bordas da imagem habitualmente deixada em branco por desenvolvedores, que por vezes também contêm pixels de lixo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, + "Adiciona um leve embaciado à imagem para suavizar as arestas da borda dos pixels. Esta opção tem pouco impacto no desempenho." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FILTER, + "Aplica um filtro de vídeo processado pela CPU. OBS: Pode vir a um alto custo de desempenho. Alguns filtros de vídeo podem funcionar apenas para núcleos que usam cores de 32 bits ou 16 bits." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, + "Insira o nome de usuário de sua conta Retro Achievements." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, + "Insira a senha de sua conta Retro Achievements." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, + "Insira seu nome de usuário aqui. Isto será utilizado para sessões do Netplay, entre outras coisas." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, + "Capturar a imagem depois que os filtros (mas não os Shaders) forem aplicados. Seu vídeo ficará tão elegante quanto o que você vê na tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST, + "Selecionar qual núcleo utilizar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, + "Selecionar qual conteúdo iniciar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, + "Exibir interfaces de rede e endereços de IP associados." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, + "Exibir informações específicas do dispositivo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUIT_RETROARCH, + "Sair do programa." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, + "Define a largura personalizada para a janela de exibição. Deixado em 0 a janela irá dimensionar o mais largo possível." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, + "Define a altura personalizada para a janela de exibição. Deixado em 0 a janela irá dimensionar o mais alto possível." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, + "Define a largura personalizada para o modo de tela cheia em não-janela. Deixar em 0 irá usar a resolução da área de trabalho." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, + "Define a altura personalizada para o modo de tela cheia em não-janela. Deixar em 0 irá usar a resolução da área de trabalho." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, + "Especifique a posição personalizada no eixo X para o texto na tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, + "Especifique a posição personalizada no eixo Y para o texto na tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, + "Especifique o tamanho da fonte em pontos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, + "Ocultar a Transparência enquanto estiver dentro do menu e exibir novamente ao sair." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Exibir comandos de teclado/controle na transparência." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Selecione a porta para a transparência escutar se Exibir Comandos na Transparência estiver habilitado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, + "O conteúdo analisado aparecerá aqui." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, + "Apenas dimensiona o vídeo em valores inteiros. O tamanho de base depende da geometria relatada pelo sistema e da proporção de tela. Se 'Forçar Proporção' não estiver definido, X / Y serão dimensionados independentemente em valores inteiros." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_GPU_SCREENSHOT, + "Captura a tela com Shader de GPU se disponível." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_ROTATION, + "Força uma certa rotação da tela. A rotação é adicionada a rotação que o núcleo definir." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FORCE_SRGB_DISABLE, + "Desabilita de forma forçada o suporte sRGB FBO. Alguns drivers Intel OpenGL no Windows possuem problemas de vídeo com o suporte sRGB FBO se estiver habilitado. Habilitando isto pode contornar o problema." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN, + "Inicia em tela cheia. Pode ser mudado a qualquer momento." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOWED_FULLSCREEN, + "Se estiver em tela cheia, prefira utilizar uma janela de tela cheia." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_GPU_RECORD, + "Grava o material de saída do Shader de GPU se disponível." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, + "Ao criar um Estado de Jogo, o índice do Estado de Jogo é aumentado automaticamente antes de ser salvo. Ao carregar um conteúdo, o índice será definido para o índice mais alto existente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, + "Bloqueia a SRAM de ser sobrescrita ao carregar um Estado de Jogo. Pode causar problemas no jogo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FASTFORWARD_RATIO, + "Taxa máxima em que o conteúdo será executado quando utilizado o Avanço Rápido (ex: 5.0x para conteúdos em 60fps = 300 fps máx). Se for definido como 0.0x, a taxa de Avanço Rápido é ilimitada (sem FPS máx)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, + "Quando está em Câmera Lenta, o conteúdo será diminuído pelo fator especificado/definido." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN_AHEAD_ENABLED, + "Executar o núcleo lógico um ou mais quadros à frente e carreguar o estado de volta para reduzir o atraso dos controles percebido." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN_AHEAD_FRAMES, + "O número de quadros para avançar. Causa problemas de jogabilidade, como instabilidade, se você exceder o número de quadros de atraso internos do jogo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN_AHEAD_SECONDARY_INSTANCE, + "Usa uma segunda instância do núcleo do RetroArch para avançar quadros. Evita problemas de áudio devido ao estado de carregamento." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS, + "Oculta a mensagem de aviso que aparece ao usar o Adiantar Quadro e o núcleo não suporta Estados de Jogo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_ENABLE, + "Habilita a rebobinamento. Isso irá impactar o desempenho ao jogar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_TOGGLE, + "Aplicar a trapaça imediatamente após alternância." +) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_LOAD, + "Aplicar trapaças automaticamente quando o jogo for carregado." +) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, + "Ao definir um número de quadros para o rebobinamento, você pode retroceder vários quadros de uma só vez, aumentando a velocidade da função." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE, + "A quantidade de memória (em MB) para reservar ao buffer de rebobinamento . Aumentar esse valor aumentará a quantidade de histórico do rebobinamento." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE_STEP, + "Sempre que você aumentar ou diminuir o valor do tamanho do buffer do rebobinamento por meio dessa interface, ele será alterado por esse valor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_IDX, + "Posição do índice na lista." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_ADDRESS_BIT_POSITION, + "Bitmask o endereço quando o tamanho da busca da memória for < 8-bit." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_MATCH_IDX, + "Selecionar a coincidência para visualizar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_START_OR_CONT, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_START_OR_RESTART, + "Esquerda/Direita para alterar o tamanho do bit" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EXACT, + "Esquerda/Direita para alterar o valor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_LT, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_GT, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_LTE, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_GTE, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQ, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_NEQ, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQPLUS, + "Esquerda/Direita para alterar o valor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQMINUS, + "Esquerda/Direita para alterar o valor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_ADD_MATCHES, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_VIEW_MATCHES, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_CREATE_OPTION, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_DELETE_OPTION, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_ADD_NEW_TOP, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_ADD_NEW_BOTTOM, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_DELETE_ALL, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_RELOAD_CHEATS, + "" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_BIG_ENDIAN, + "Big endian : 258 = 0x0102,\nLittle endian : 258 = 0x0201" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, + "Define o nível de registro de eventos para os núcleos. Se o nível do registro enviado por um núcleo for abaixo deste valor, o mesmo é ignorado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PERFCNT_ENABLE, + "Habilitar os contadores de desempenho para o RetroArch (e núcleos)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, + "Cria automaticamente um Estado de Jogo no final da execução do RetroArch. O RetroArch irá carregar automaticamente este Estado de Jogo se a função 'Autocarregar Estado de Jogo' estiver habilitada." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, + "Carrega automaticamente o último Estado de Jogo auto salvo na inicialização do RetroArch." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE, + "Mostrar miniaturas de estados salvos dentro do menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, + "Salvar automaticamente o Save RAM não-volátil em um intervalo regular. Isso está desabilitado por padrão, a menos que seja definido de outra forma. O intervalo é medido em segundos. Um valor de 0 desativa o salvamento automático." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, + "Se ativado, substitui os vínculos de entrada com as associações remapeadas definidas para o núcleo atual." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_AUTODETECT_ENABLE, + "Habilita a detecção automática de entrada. Tentará configurar automaticamente joypads, estilo Plug-and-Play." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_INPUT_SWAP_OK_CANCEL, + "Troca de botões para OK/Cancelar. Desabilitado é o estilo de botão japonês, habilitada é oestilo ocidental." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, + "Se desabilitado, o conteúdo continuará sendo executado em segundo plano quando o menu do RetroArch for alternado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_DRIVER, + "Driver de vídeo para usar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_DRIVER, + "Driver de áudio para usar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DRIVER, + "Driver de entrada para usar. Dependendo do driver de vídeo, pode forçar um driver de entrada diferente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, + "Driver do Joypad para usar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_DRIVER, + "Driver de reamostragem de áudio a ser utilizado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CAMERA_DRIVER, + "Driver de câmera a ser utilizado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOCATION_DRIVER, + "Driver de localização a ser utilizado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_DRIVER, + "Driver de menu a ser utilizado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORD_DRIVER, + "Driver de gravação a ser utilizado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIDI_DRIVER, + "Driver MIDI a ser utilizado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_WIFI_DRIVER, + "Driver de WiFi a ser utilizado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Filtra os arquivos em exibição no explorador de arquivos por extensões suportadas." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WALLPAPER, + "Seleciona uma imagem para definir como plano de fundo do menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER, + "Carrega dinamicamente um novo plano de fundo dependendo do contexto." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_DEVICE, + "Substitui o dispositivo de áudio padrão utilizado pelo driver de áudio. Isto depende do driver." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN, + "Plugin DSP de Áudio que processa o áudio antes de ser enviado para o driver." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_OUTPUT_RATE, + "Taxa de amostragem da saída de áudio." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, + "Opacidade de todos os elementos de interface da Transparência." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_SCALE, + "Escala de todos os elementos de interface da Transparência." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ENABLE, + "Habilita a Transparência." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_PRESET, + "Seleciona uma Transparência pelo navegador de arquivos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, + "Endereço do hospedeiro a se conectar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT, + "Porta do endereço de IP do hospedeiro. Pode ser uma porta TCP ou uma porta UDP." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, + "Senha para conectar ao hospedeiro de Netplay. Utilizado apenas no modo hospedeiro." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, + "Anunciar os jogos de Netplay publicamente. Se não for definido, os clientes deverão conectar manualmente em vez de usar o lobby público." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, + "Senha para conectar ao hospedeiro de Netplay apenas com privilégios de espectador. Utilizado apenas no modo hospedeiro." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_START_AS_SPECTATOR, + "Define se o Netplay deve iniciar em modo espectador." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_SLAVES, + "Define se conexões em modo escravo são permitidas. Clientes em modo escravo requerem muito pouco poder de processamento em ambos os lados, mas irão sofrer significamente da latência de rede." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_REQUIRE_SLAVES, + "Define se conexões que não estão em modo escravo são proibidas. Não recomendado, exceto para redes muito rápidas com máquinas muito lentas." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_STATELESS_MODE, + "Define se deve executar o Netplay em modo que não utilize Estados de Jogo. Se definido como verdadeiro, uma rede muito rápida é necessária, mas nenhum rebobinamento é realizado, portanto, não haverá instabilidade no jogo em rede." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_CHECK_FRAMES, + "Frequência em quadros no qual o Netplay verificará se o hospedeiro e o cliente estão sincronizados." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_NAT_TRAVERSAL, + "Ao hospedar uma partida, tente receber conexões da Internet pública usando UPnP ou tecnologias similares para escapar das redes locais." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, + "Habilitar interface de comando stdin." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MOUSE_ENABLE, + "Habilitar controle por Mouse dentro do menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_POINTER_ENABLE, + "Habilitar controle por toque dentro do menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_THUMBNAILS, + "Tipo de miniatura a ser exibida." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, + "Tipo de miniatura para exibir à esquerda." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_VERTICAL_THUMBNAILS, + "Exibe a miniatura esquerda sob a direita, no lado direito da tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE, + "Exibir data e/ou hora atuais dentro do menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE, + "Exibir o nível de bateria atual dentro do menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NAVIGATION_WRAPAROUND, + "Voltar ao início ou final se o limite da lista for alcançado horizontalmente ou verticalmente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, + "Habilita o Netplay no modo hospedeiro (servidor)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_CLIENT, + "Habilita o Netplay no modo cliente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_DISCONNECT, + "Desconecta de uma conexão de Netplay ativa." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCAN_DIRECTORY, + "Analisa um diretório por arquivos compatíveis e os adiciona à coleção." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCAN_FILE, + "Analisa um arquivo compatível e o adiciona à coleção." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SWAP_INTERVAL, + "Usa um intervalo de troca personalizado para V-Sync. Defina para reduzir efetivamente a taxa de atualização do monitor pela metade." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SORT_SAVEFILES_ENABLE, + "Ordenar os Jogos-Salvos em pastas com o nome do núcleo utilizado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE, + "Ordenar os Estados de Jogo em pastas com o nome do núcleo utilizado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_REQUEST_DEVICE_I, + "Solicitar jogar com o dispositivo de entrada dado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, + "URL para o diretório de atualização de núcleos no buildbot do Libreto." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL, + "URL para o diretório de atualizações de recursos no buildbot do Libretro." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Após o download, extrair automaticamente os arquivos contidos nos arquivos comprimidos baixados." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, + "Analisar por novas salas." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DELETE_ENTRY, + "Remover esta entrada da coleção." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INFORMATION, + "Visualizar mais informações sobre o conteúdo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES, + "Adicionar o item aos seus favoritos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES_PLAYLIST, + "Adicionar o item aos seus favoritos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN, + "Iniciar o conteúdo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, + "Ajustar as definições do navegador de arquivos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, + "Habilitar por padrão controles personalizados na inicialização." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, + "Habilitar por padrão configuração personalizada na inicialização." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, + "Habilitar por padrão opções de núcleo personalizadas na inicialização." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_ENABLE, + "Exibir o nome do núcleo atual dentro do menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DATABASE_MANAGER, + "Visualizar bases de dados." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CURSOR_MANAGER, + "Visualizar pesquisas anteriores." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, + "Captura uma imagem da tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOSE_CONTENT, + "Fecha o conteúdo atual. Alterações não salvas serão perdidas." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOAD_STATE, + "Carregar um Estado de Jogo do compartimento selecionado atualmente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_STATE, + "Salvar um Estado de Jogo no compartimento selecionado atualmente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESUME, + "Retomar a execução do conteúdo atual e sair do Menu Rápido." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESUME_CONTENT, + "Retomar a execução do conteúdo atual e sair do Menu Rápido." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STATE_SLOT, + "Altera o compartimento do Estado de Jogo selecionado atualmente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE, + "Se um Estado de Jogo for carregado, o conteúdo voltará ao estado anterior ao carregamento." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, + "Se o Estado de Jogo foi sobrescrito, ele voltará ao Estado de Jogo salvo anteriormente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, + "Serviço Retro Achievements. Para mais informações, visite http://retroachievements.org (em inglês)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, + "Gerencia as contas configuradas atualmente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_REWIND, + "Gerencia as configurações do rebobinamento." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_DETAILS, + "Gerencia as configurações dos detalhes da trapaça." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_SEARCH, + "Inicia ou continua uma pesquisa de código de trapaça." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESTART_CONTENT, + "Reinicia o conteúdo do começo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Salva um arquivo de redefinição de configuração que será aplicado a todo o conteúdo carregado por este núcleo. Terá prioridade sobre a configuração principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, + "Salva um arquivo de redefinição de configuração que será aplicado a todo o conteúdo carregado no mesmo diretório que o arquivo atual. Terá prioridade sobre a configuração principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, + "Salva um arquivo de redefinição de configuração que será aplicado apenas ao conteúdo atual. Terá prioridade sobre a configuração principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, + "Configurar códigos de Trapaça." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHADER_OPTIONS, + "Configurar Shader para realçar a aparência da imagem." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, + "Alterar os controles para o conteúdo que está sendo executado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_OPTIONS, + "Alterar as opções para o conteúdo que está sendo executado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, + "Exibir as configurações avançadas para usuários experientes (oculto por padrão)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, + "Executar tarefas em linhas de processamento paralelas." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, + "Permitir que o usuário possa remover itens das coleções." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, + "Define o diretório de sistema. Os núcleos podem consultar este diretório para carregar arquivos de BIOS, configurações específicas do sistema, etc." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, + "Define o diretório inicial do navegador de arquivos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_DIR, + "Usualmente definido por desenvolvedores que agrupam aplicativos Libretro/RetroArch para apontar para os recursos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPERS_DIRECTORY, + "Diretório para armazenar planos de fundo dinamicamente carregados pelo menu dependendo do contexto." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_THUMBNAILS_DIRECTORY, + "Miniaturas auxiliares (arte da embalagem/imagens diversas e etc.) são armazenadas aqui." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, + "Define o diretório inicial para o navegador de configurações do menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "O número de quadros de latência de entrada para o Netplay utilizar para mascarar a latência da rede. Reduz a oscilação e torna o Netplay menos intensivo para a CPU, ao custo de atraso perceptível na entrada." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "O intervalo de quadros de latência de entrada que pode ser utilizado para mascarar a latência da rede. Reduz a oscilação e torna o Netplay menos intensivo para a CPU, ao custo de atraso imprevisível na entrada." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISK_CYCLE_TRAY_STATUS, + "Alterna o disco atual. Se o disco estiver inserido, o mesmo será ejetado. Se o disco não estiver inserido, o mesmo será inserido." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISK_INDEX, + "Mudar o índice do disco." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISK_OPTIONS, + "Gerenciamento de imagem de disco." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISK_IMAGE_APPEND, + "Selecione uma imagem de disco para inserir." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_ENUM_THROTTLE_FRAMERATE, + "Certifica-se de que a taxa de quadros é controlada enquanto estiver dentro do menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VRR_RUNLOOP_ENABLE, + "Não desviar dos tempos solicitado pelo núcleo. Usar com telas de Taxa de Atualização Variável, G-Sync, FreeSync." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_LAYOUT, + "Selecione um layout diferente para a interface XMB." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_THEME, + "Selecionar um tema diferente para os ícones. As alterações terão efeito após reiniciar o programa." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE, + "Habilitar as sombras para todos os ícones. Isto terá um pequeno impacto no desempenho." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME, + "Selecionar um tema de gradiente de cor de plano de fundo diferente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY, + "Modificar a opacidade do plano de fundo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_MENU_COLOR_THEME, + "Selecionar um tema de gradiente de cor de plano de fundo diferente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, + "Selecionar um efeito de plano de fundo animado. Pode exigir mais processamento da GPU dependendo do efeito. Se o desempenho for insatisfatório, desligue este efeito ou reverta para um efeito mais simples." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_FONT, + "Selecionar uma fonte principal diferente para ser usada pelo menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_FAVORITES, + "Exibir a aba de favoritos dentro do menu principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, + "Exibir a aba de imagem dentro do menu principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, + "Exibir a aba de música dentro do menu principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, + "Exibir a aba de vídeo dentro do menu principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, + "Exibir a aba de Netplay dentro do menu principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS, + "Mostrar a aba de configurações dentro do menu principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_HISTORY, + "Mostrar a aba de histórico recente dentro do menu principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, + "Mostrar a aba de importação de conteúdo dentro do menu principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, + "Exibir abas da lista de reprodução dentro do menu principal." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, + "Exibir a tela inicial no menu. É automaticamente definido como falso após o programa iniciar pela primeira vez." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, + "Modificar a opacidade do gráfico do cabeçalho." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, + "Modificar a opacidade do gráfico do rodapé." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DPI_OVERRIDE_ENABLE, + "O menu normalmente se dimensiona dinamicamente. Se você desejar definir uma escala de tamanho específica em vez disto, habilite esta função." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DPI_OVERRIDE_VALUE, + "Definir o tamanho do dimensionamento personalizado aqui. OBS: Você deve habilitar a função 'Redefinição de DPI' para que este dimensionamento tenha efeito." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, + "Salvar todos os arquivos baixados neste diretório." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_REMAPPING_DIRECTORY, + "Salvar todos os controles remapeados neste diretório." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, + "Diretório onde o programa busca por conteúdo/núcleos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LIBRETRO_INFO_PATH, + "Os arquivos de informação do aplicativo/núcleo são armazenados aqui." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, + "Se um Joypad estiver conectado, o mesmo será autoconfigurado se um arquivo de configuração correspondente estiver presente dento deste diretório." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_DIRECTORY, + "Salvar todas as coleções neste diretório." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, + "Se for definido um diretório, o conteúdo que é temporariamente extraído (ex: dos arquivos) sera extraído para este diretório." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CURSOR_DIRECTORY, + "As consultas salvas são armazenadas neste diretório." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, + "As bases de dados são armazenadas neste diretório." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, + "Esta localização é consultada por padrão quando a interface do menu tenta procurar por recursos carregáveis, etc." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVEFILE_DIRECTORY, + "Salvar todos os Jogos-Salvos neste diretório. Se não for definido, tentaremos salvar dentro do diretório de trabalho do arquivo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_DIRECTORY, + "Salvar todos os Estados de Jogo neste diretório. Se não for definido, tentaremos salvar dentro do diretório de trabalho do arquivo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, + "Diretório para armazenar as capturas de tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_DIRECTORY, + "Define um diretório onde as Transparências são mantidas para fácil acesso." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_DATABASE_PATH, + "Os arquivos de Trapaça são mantidos aqui." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_FILTER_DIR, + "Diretório onde os arquivos de filtro DSP de áudio são mantidos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FILTER_DIR, + "Diretório onde os arquivos de filtro de vídeo processado por CPU são mantidos." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_DIR, + "Define um diretório onde os arquivos de Shader de vídeo processado por GPU são mantidos para fácil acesso." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORDING_OUTPUT_DIRECTORY, + "As gravações serão armazenadas neste diretório." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORDING_CONFIG_DIRECTORY, + "As configurações de gravação serão mantidas aqui." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FONT_PATH, + "Selecionar uma fonte diferente para as notificações na tela." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHADER_APPLY_CHANGES, + "As alterações das configurações de Shader terão efeito imediato. Use isto se você alterou a quantidade de estágios de Shader, filtros, escala FBO, etc." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_NUM_PASSES, + "Aumentar ou diminuir a quantidade de estágios do pipeline de Shader. Você pode adicionar um Shader separado para cada estágio do pipeline e configurar sua escala e filtro." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET, + "Carregar uma predefinição de Shader. O pipeline de Shader será definido automaticamente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_AS, + "Salvar as definições de Shader atuais como uma nova predefinição de Shader." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, + "Salvar as definições de Shader atuais como a definição padrão para esta aplicação/núcleo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_PARENT, + "Salve as configurações atuais do shader como as configurações padrão para todos os arquivos no diretório de conteúdo atual." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, + "Salvar as definições de Shader atuais como a definição padrão para o conteúdo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, + "Modifica diretamente o Shader atual. As alterações não serão salvas no arquivo de predefinição." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PARAMETERS, + "Modifica a predefinição de Shader atualmente utilizada no menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, + "Aumentar ou diminuir a quantidade de Trapaças." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_APPLY_CHANGES, + "As alterações de Trapaça terão efeito imediato." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_START_SEARCH, + "Iniciar a procura por uma nova trapaça. O número de bits pode ser alterado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_CONTINUE_SEARCH, + "Continuar procurando por uma nova trapaça." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, + "Carregar um arquivo de Trapaça." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD_APPEND, + "Carreguar um arquivo de trapaça e anexar às trapaças existentes." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_SAVE_AS, + "Salvar as Trapaças atuais como um arquivo de Jogo-Salvo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SETTINGS, + "Acessar rapidamente todas as configurações relevantes ao jogo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INFORMATION, + "Visualizar informações sobre a aplicação/núcleo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO, + "Valor em ponto flutuante da proporção de tela (largura / altura), utilizado se Proporção de Tela estiver definido como 'Configuração'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, + "Personalizar a altura da janela de exibição que é usada se a Proporção de Tela estiver definida como 'Personalizada'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, + "Personalizar a largura da janela de exibição que é usada se a Proporção de Tela estiver definida como 'Personalizada'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, + "Deslocamento personalizado no eixo-X da janela de exibição. Será ignorado se a 'Escala em Inteiros' estiver habilitada. Neste caso ela será centralizada automaticamente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, + "Deslocamento personalizado no eixo-Y da janela de exibição. Será ignorado se a 'Escala em Inteiros' estiver habilitada. Neste caso ela será centralizada automaticamente." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, + "Utilizar Servidor MITM" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, + "Encaminhar conexões do Netplay através de um servidor 'homem no meio' (MITM). Útil se o hospedeiro estiver atrás de um firewall ou tiver problemas de NAT/UPnP." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER, + "Localização do Servidor de Retransmissão" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_MITM_SERVER, + "Escolha um servidor de retransmissão específico para usar. Locais geograficamente mais próximos tendem a ter menor latência." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, + "Adicionar ao mixer" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_PLAY, + "Adicionar ao mixer e reproduzir" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION, + "Adicionar ao mixer" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY, + "Adicionar ao mixer e reproduzir" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "Filtrar por núcleo atual" + ) +MSG_HASH( + MSG_AUDIO_MIXER_VOLUME, + "Volume global do mixer de áudio" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, + "Volume global do mixer de áudio (em dB). 0dB é o volume normal, e nenhum ganho será aplicado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, + "Nível de Volume do Mixer de Áudio (dB)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, + "Mixer de Áudio Mudo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, + "Mixer de áudio mudo/não-mudo." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_ONLINE_UPDATER, + "Exibir Atualizador Online" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, + "Exibir/ocultar a opção 'Atualizador Online'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_VIEWS_SETTINGS, + "Visualizações" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_VIEWS_SETTINGS, + "Exibir elementos na tela de menu." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, + "Exibir Atualizador de Núcleos" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, + "Exibir/ocultar a opção de atualizar núcleos (e arquivos de informação de núcleo)." + ) +MSG_HASH( + MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparando a busca de conteúdo..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Remover núcleo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remover este núcleo do disco." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Opacidade do Framebuffer" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modificar a opacidade do framebuffer." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favoritos" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Conteúdo adicionado aos 'Favoritos' vai aparecer aqui." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Músicas" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Músicas que foram reproduzidas aparecem aqui." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Imagens" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Imagens que foram exibidas aparecem aqui." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Vídeos" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Vídeos que foram reproduzidos aparecem aqui." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Ícones do Menu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Habilitar/desabilitar os ícones exibidos do lado esquerdo dos itens de menu." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MAIN_MENU_ENABLE_SETTINGS, + "Habilitar aba de configurações" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS_PASSWORD, + "Definir senha para habilitar aba de configurações" + ) +MSG_HASH( + MSG_INPUT_ENABLE_SETTINGS_PASSWORD, + "Digite a senha" + ) +MSG_HASH( + MSG_INPUT_ENABLE_SETTINGS_PASSWORD_OK, + "Senha correta." + ) +MSG_HASH( + MSG_INPUT_ENABLE_SETTINGS_PASSWORD_NOK, + "Senha incorreta." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_MAIN_MENU_ENABLE_SETTINGS, + "Habilita a aba de configurações. É necessário reiniciar para que a aba apareça." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS_PASSWORD, + "O fornecimento de uma senha ao ocultar a aba de configurações permite restaurar mais tarde a partir do menu, indo para a aba Menu Principal, selecionando Habilitar aba configurações e inserindo a senha." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, + "Permita que o usuário renomeie os itens nas coleções." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Permitir renomear itens" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RENAME_ENTRY, + "Renomear o título do item." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RENAME_ENTRY, + "Renomear" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CORE, + "Exibir 'Carregar Núcleo'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CORE, + "Exibir/ocultar a opção 'Carregar Núcleo'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CONTENT, + "Exibir Carregar Conteúdo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CONTENT, + "Exibir/ocultar a opção 'Carregar Conteúdo'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_INFORMATION, + "Exibir Informação" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_INFORMATION, + "Exibir/ocultar a opção 'Informação'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_CONFIGURATIONS, + "Exibir Configurações" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_CONFIGURATIONS, + "Exibir/ocultar a opção 'Configurações'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_HELP, + "Exibir Ajuda" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_HELP, + "Exibir/ocultar a opção 'Ajuda'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_QUIT_RETROARCH, + "Exibir Sair do RetroArch" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_QUIT_RETROARCH, + "Exibir/ocultar a opção 'Sair do RetroArch'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_REBOOT, + "Exibir Reiniciar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_REBOOT, + "Exibir/ocultar a opção 'Reiniciar'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_SHUTDOWN, + "Exibir Desligar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_SHUTDOWN, + "Exibir/ocultar a opção 'Desligar'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_VIEWS_SETTINGS, + "Menu Rápido" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_VIEWS_SETTINGS, + "Exibir ou ocultar elementos na tela de Menu Rápido." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_TAKE_SCREENSHOT, + "Exibir 'Captura de Tela'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_TAKE_SCREENSHOT, + "Exibir/ocultar a opção 'Captura de Tela'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_LOAD_STATE, + "Exibir Salvar/Carregar Estado" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, + "Exibir/ocultar as opções para salvar/carregar estados." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, + "Exibir Desfazer Salvar/Carregar Estado" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, + "Exibir/ocultar as opções para abolir o salvar/carregar estado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_FAVORITES, + "Exibir Adicionar aos Favoritos" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, + "Exibir/ocultar a opção 'Adicionar aos Favoritos'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_OPTIONS, + "Exibir Opções" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_OPTIONS, + "Exibir/ocultar a opção 'Opções'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CONTROLS, + "Exibir Controles" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CONTROLS, + "Exibir/ocultar a opção 'Controles'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CHEATS, + "Exibir Trapaças" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CHEATS, + "Exibir/ocultar a opção 'Trapaças'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SHADERS, + "Exibir 'Shaders'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SHADERS, + "Exibir/ocultar a opção 'Shaders'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, + "Exibir Salvar Redefinição de Núcleo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, + "Exibir/ocultar a opção 'Salvar Redefinição de Núcleo'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, + "Exibir Salvar Redefinição de Jogo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, + "Exibir/ocultar a opção 'Salvar Redefinição de Jogo'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_INFORMATION, + "Exibir Informação" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_INFORMATION, + "Exibir/ocultar a opção 'Informação'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_ENABLE, + "Ativar Notificação de Fundo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_RED, + "Notificação de Fundo em Cor Vermelha" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_GREEN, + "Notificação de Fundo em Cor Verde" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_BLUE, + "Notificação de Fundo em Cor Azul" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_OPACITY, + "Opacidade da Notificação de Fundo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_DISABLE_KIOSK_MODE, + "Desabilitar o Modo Quiosque" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_DISABLE_KIOSK_MODE, + "Desabilita o Modo Quiosque. É necessária uma reinicialização para que a mudança tenha total efeito." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_ENABLE_KIOSK_MODE, + "Habilitar o Modo Quiosque" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_ENABLE_KIOSK_MODE, + "Protege a configuração escondendo todas as configurações relacionadas à configuração." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_KIOSK_MODE_PASSWORD, + "Definir senha para desabilitar o Modo Quiosque" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_KIOSK_MODE_PASSWORD, + "Fornecer uma senha ao habilitar o Modo Quiosque tornando possível desabilitar mais tarde a partir do menu, indo para o Menu Principal, selecionando Desabilitar o Modo Quiosque e inserindo a senha." + ) +MSG_HASH( + MSG_INPUT_KIOSK_MODE_PASSWORD, + "Digite a Senha" + ) +MSG_HASH( + MSG_INPUT_KIOSK_MODE_PASSWORD_OK, + "Senha correta." + ) +MSG_HASH( + MSG_INPUT_KIOSK_MODE_PASSWORD_NOK, + "Senha incorreta." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_RED, + "Notificação em Cor Vermelha" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_GREEN, + "Notificação em Cor Verde" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_BLUE, + "Notificação em Cor Azul" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRAMECOUNT_SHOW, + "Exibir contagem de quadros na tela FPS" + ) +MSG_HASH( + MSG_CONFIG_OVERRIDE_LOADED, + "Substituição de configuração carregada." + ) +MSG_HASH( + MSG_GAME_REMAP_FILE_LOADED, + "Arquivo de remapeamento do jogo carregado." + ) +MSG_HASH( + MSG_CORE_REMAP_FILE_LOADED, + "Arquivo de remapeamento principal carregado." + ) +MSG_HASH( + MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, + "O Adiantar Quadro foi desativado porque esse núcleo não suporta estados de jogo." + ) +MSG_HASH( + MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, + "Falha ao salvar o estado do jogo. O Adiantar Quadro foi desativado." + ) +MSG_HASH( + MSG_RUNAHEAD_FAILED_TO_LOAD_STATE, + "Falha ao carregar o estado do jogo. O Adiandar Quadro foi desativado." + ) +MSG_HASH( + MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE, + "Falha ao criar uma segunda instância. O Adiantar Quadro agora usará apenas uma instância." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, + "Adicione automaticamente conteúdo à lista de reprodução" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTOMATICALLY_ADD_CONTENT_TO_PLAYLIST, + "Verifica automaticamente o conteúdo carregado para que eles apareçam dentro das listas de reprodução." + ) +MSG_HASH( + MSG_SCANNING_OF_FILE_FINISHED, + "Verificação do arquivo terminado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_OPACITY, + "Opacidade da Janela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_QUALITY, + "Qualidade da Reamostragem do Áudio" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_QUALITY, + "Abaixe esse valor para favorecer o desempenho/baixa latência em relação à qualidade de áudio, aumente se desejar melhor qualidade de áudio à custa do desempenho/baixa latência." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_WATCH_FOR_CHANGES, + "Ver arquivos de shader para mudanças" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, + "Aplicar automaticamente as alterações feitas nos arquivos de shader no disco." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SHOW_DECORATIONS, + "Exibir Decorações da Janela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STATISTICS_SHOW, + "Exibir estatísticas" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STATISTICS_SHOW, + "Mostrar estatísticas técnicas na tela." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_ENABLE, + "Ativar preenchimento de borda" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, + "Ativar espessura de preenchimento de borda" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, + "Ativar espessura de preenchimento do plano de fundo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION, + "Para monitores CRT de 15 kHz apenas. Tenta usar a resolução exata do núcleo/jogo e a taxa de atualização." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION, + "Trocar para Resolução CRT" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_SUPER, + "Quando Trocar para Resolução CRT está ativada, força a resolução horizontal ultrawide para minimizar a alternância de modo." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, + "Super Resolução CRT" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, + "Exibir Configurações de Rebobinamento" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, + "Exibir/ocultar as opções de Rebobinamento." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_LATENCY, + "Exibir/ocultar as opções de Latência." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_LATENCY, + "Exibir Configurações de Latência" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_OVERLAYS, + "Exibir/ocultar as opções de Sobreposição." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_OVERLAYS, + "Exibir Configurações de Sobreposição" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE_MENU, + "Ativar áudio de menu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_ENABLE_MENU, + "Ativar ou desativar o som do menu." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_SETTINGS, + "Configurações do Mixer" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MIXER_SETTINGS, + "Visualizar e/ou modificar as configurações do mixer de áudio." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_INFO, + "Informação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE, + "&Arquivo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_LOAD_CORE, + "&Carregar Núcleo..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_UNLOAD_CORE, + "&Descarregar Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_EXIT, + "Sai&r" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT, + "&Editar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_EDIT_SEARCH, + "&Pesquisar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW, + "&Visualizar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_CLOSED_DOCKS, + "Docas Fechadas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_SHADER_PARAMS, + "Parâmetros do Shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS, + "&Opções..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS, + "Lembrar Posições da Doca:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY, + "Lembrar Geometria da Janela:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB, + "Lembrar a Última Aba do Navegador de Conteúdo:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME, + "Tema" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK, + "Escuro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM, + "Personalizado..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE, + "Opções" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_TOOLS, + "&Ferramentas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP, + "&Ajuda" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT, + "Sobre o RetroArch" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_DOCUMENTATION, + "Documentação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOAD_CUSTOM_CORE, + "Carregar Núcleo Personalizado..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOAD_CORE, + "Carregar Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOADING_CORE, + "Carregando Núcleo..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_NAME, + "Nome" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE_VERSION, + "Versão" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_TAB_PLAYLISTS, + "Listas de Reprodução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER, + "Navegador de Arquivos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_TOP, + "Topo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_UP, + "Subir" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER, + "Navegador de Conteúdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_BOXART, + "Arte da Capa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_SCREENSHOT, + "Captura de Tela" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, + "Tela de Título" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, + "Todas as Listas de Reprodução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE, + "Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE_INFO, + "Informação do Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE_SELECTION_ASK, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_INFORMATION, + "Informação" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_WARNING, + "Advertência" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ERROR, + "Erro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR, + "Erro de Rede" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESTART_TO_TAKE_EFFECT, + "Por favor, reinicie o programa para que as alterações entrem em vigor." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOG, + "Relatório" + ) #ifdef HAVE_QT -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, - "Verificação Terminada.

    \n" - "Para que o conteúdo seja verificado corretamente, você deve em ordem:\n" - "
    • ter um núcleo compatível já baixado
    • \n" - "
    • ter os \"Arquivos de Informação de Núcleo\" atualizados via Atualizador Online
    • \n" - "
    • ter a \"Base de Dados\" atualizada via Atualizador Online
    • \n" - "
    • reiniciar o RetroArch caso alguma das situações acima tenha sido feita
    \n" - "E finalmente, o conteúdo deve corresponder as bases de dados existentes aqui. Se ainda não estiver funcionando, considere enviar um relatório de erro.") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, + "Verificação Terminada.

    \n" + "Para que o conteúdo seja verificado corretamente, você deve em ordem:\n" + "
    • ter um núcleo compatível já baixado
    • \n" + "
    • ter os \"Arquivos de Informação de Núcleo\" atualizados via Atualizador Online
    • \n" + "
    • ter a \"Base de Dados\" atualizada via Atualizador Online
    • \n" + "
    • reiniciar o RetroArch caso alguma das situações acima tenha sido feita
    \n" + "E finalmente, o conteúdo deve corresponder as bases de dados existentes aqui. Se ainda não estiver funcionando, considere enviar um relatório de erro." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + "Exibir Menu Desktop" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_WIMP, + "Abre o menu desktop se estiver fechado." + ) #endif -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, - "Não mostrar isto novamente") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_STOP, - "Parar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ASSOCIATE_CORE, - "Associar Núcleo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS, - "Ocultar Listas de Reprodução") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_HIDE, - "Ocultar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR, - "Cor de Destaque") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CHOOSE, - "&Escolher...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SELECT_COLOR, - "Selecionar Cor") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SELECT_THEME, - "Selecionar Tema") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CUSTOM_THEME, - "Tema Personalizado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_PATH_IS_BLANK, - "O caminho do arquivo está em branco.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_IS_EMPTY, - "O arquivo está vazio.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED, - "Não foi possível abrir o arquivo para leitura.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST, - "O arquivo não existe.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST, - "Sugerir Primeiro Núcleo Carregado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QUICK_MENU_OVERRIDE_OPTIONS, - "Opções de Substituição de Configuração") -MSG_HASH(MENU_ENUM_SUBLABEL_QUICK_MENU_OVERRIDE_OPTIONS, - "Opções para substituir a configuração global.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY, - "Irá iniciar a reprodução do fluxo de áudio. Uma vez terminado, removerá o fluxo de áudio atual da memória.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_LOOPED, - "Irá iniciar a reprodução do fluxo de áudio. Uma vez terminado, ele fará um loop e reproduzirá a faixa novamente desde o começo.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_SEQUENTIAL, - "Irá iniciar a reprodução do fluxo de áudio. Uma vez terminado, ele irá pular para o próximo fluxo de áudio em ordem sequencial e repetirá este comportamento. Útil como um modo de reprodução de álbum.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_STOP, - "Isso interromperá a reprodução do fluxo de áudio, mas não o removerá da memória. Você pode começar a reproduzi-lo novamente selecionando 'Reproduzir'.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_REMOVE, - "Isso interromperá a reprodução do fluxo de áudio e o removerá completamente da memória.") -MSG_HASH(MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, - "Ajuste o volume do fluxo de áudio.") -MSG_HASH(MENU_ENUM_SUBLABEL_ADD_TO_MIXER, - "Adiciona esta faixa de áudio a um compartimento de fluxo de áudio disponível. Se nenhum compartimento estiver disponível no momento, ele será ignorado.") -MSG_HASH(MENU_ENUM_SUBLABEL_ADD_TO_MIXER_AND_PLAY, - "Adiciona esta faixa de áudio a um compartimento de fluxo de áudio disponível e reproduz. Se nenhum compartimento estiver disponível no momento, ele será ignorado.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY, - "Reproduzir") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_LOOPED, - "Reproduzir (Loop)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_SEQUENTIAL, - "Reproduzir (Sequencial)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_STOP, - "Parar") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_REMOVE, - "Remover") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_VOLUME, - "Volume") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DETECT_CORE_LIST_OK_CURRENT_CORE, - "Núcleo atual") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, - "Limpar") -MSG_HASH(MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE, - "Pausar conquistas para a sessão atual (Esta ação ativará Estados de Jogos, Trapaças, Rebobinagem, Pausa e Câmera Lenta).") -MSG_HASH(MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, - "Continuar conquistas para a sessão atual (Esta ação desabilitará Estados de Jogos, Trapaças, Rebobinagem, Pausa e Câmera Lenta e reiniciará o jogo atual).") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, - "No Menu") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, - "No Jogo") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, - "No Jogo (Pausado)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, - "Jogando") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, - "Pausado") MSG_HASH( - MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, - "Habilitar o Discord" - ) + MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, + "Não mostrar isto novamente" + ) MSG_HASH( - MENU_ENUM_SUBLABEL_DISCORD_ALLOW, - "Habilitar ou desabilitar o suporte ao Discord. Não funcionará com a versão do navegador, apenas o cliente nativo de desktop." - ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_POWER_MANAGEMENT_SETTINGS, - "Gerenciamento de Energia") -MSG_HASH(MENU_ENUM_SUBLABEL_POWER_MANAGEMENT_SETTINGS, - "Altere as configurações de gerenciamento de energia.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SUSTAINED_PERFORMANCE_MODE, - "Modo de Desempenho Sustentado") -MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_MPV_SUPPORT, - "Suporte mpv") + MENU_ENUM_LABEL_VALUE_QT_STOP, + "Parar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ASSOCIATE_CORE, + "Associar Núcleo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS, + "Ocultar Listas de Reprodução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_HIDE, + "Ocultar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR, + "Cor de Destaque" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CHOOSE, + "&Escolher..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SELECT_COLOR, + "Selecionar Cor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SELECT_THEME, + "Selecionar Tema" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CUSTOM_THEME, + "Tema Personalizado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_PATH_IS_BLANK, + "O caminho do arquivo está em branco." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_IS_EMPTY, + "O arquivo está vazio." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED, + "Não foi possível abrir o arquivo para leitura." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED, + "Não foi possível abrir o arquivo para ser gravado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST, + "O arquivo não existe." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST, + "Sugerir Primeiro Núcleo Carregado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ZOOM, + "Zoom" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_VIEW, + "Visialização" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_ICONS, + "Ícones" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_LIST, + "Lista" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_OVERRIDE_OPTIONS, + "Opções de Substituição de Configuração" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_OVERRIDE_OPTIONS, + "Opções para substituir a configuração global." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY, + "Irá iniciar a reprodução do fluxo de áudio. Uma vez terminado, removerá o fluxo de áudio atual da memória." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_LOOPED, + "Irá iniciar a reprodução do fluxo de áudio. Uma vez terminado, ele fará um loop e reproduzirá a faixa novamente desde o começo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY_SEQUENTIAL, + "Irá iniciar a reprodução do fluxo de áudio. Uma vez terminado, ele irá pular para o próximo fluxo de áudio em ordem sequencial e repetirá este comportamento. Útil como um modo de reprodução de álbum." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_STOP, + "Isso interromperá a reprodução do fluxo de áudio, mas não o removerá da memória. Você pode começar a reproduzi-lo novamente selecionando 'Reproduzir'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_REMOVE, + "Isso interromperá a reprodução do fluxo de áudio e o removerá completamente da memória." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, + "Ajuste o volume do fluxo de áudio." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_MIXER, + "Adiciona esta faixa de áudio a um compartimento de fluxo de áudio disponível. Se nenhum compartimento estiver disponível no momento, ele será ignorado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_MIXER_AND_PLAY, + "Adiciona esta faixa de áudio a um compartimento de fluxo de áudio disponível e reproduz. Se nenhum compartimento estiver disponível no momento, ele será ignorado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY, + "Reproduzir" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_LOOPED, + "Reproduzir (Loop)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_SEQUENTIAL, + "Reproduzir (Sequencial)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_STOP, + "Parar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_REMOVE, + "Remover" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIXER_ACTION_VOLUME, + "Volume" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DETECT_CORE_LIST_OK_CURRENT_CORE, + "Núcleo atual" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_SEARCH_CLEAR, + "Limpar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE, + "Pausar conquistas para a sessão atual (Esta ação ativará Estados de Jogos, Trapaças, Rebobinamento, Pausa e Câmera Lenta)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, + "Continuar conquistas para a sessão atual (Esta ação desabilitará Estados de Jogos, Trapaças, Rebobinamento, Pausa e Câmera Lenta e reiniciará o jogo atual)." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU, + "No Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME, + "No Jogo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED, + "No Jogo (Pausado)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING, + "Jogando" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED, + "Pausado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, + "Habilitar o Discord" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISCORD_ALLOW, + "Habilitar ou desabilitar o suporte ao Discord. Não funcionará com a versão do navegador, apenas o cliente nativo de desktop." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIDI_INPUT, + "Entrada" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIDI_INPUT, + "Selecionar o dispositivo de entrada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIDI_OUTPUT, + "Saída + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIDI_OUTPUT, + "Selecionar o dispositivo de saída." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MIDI_VOLUME, + "Volume" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MIDI_VOLUME, + "Definir o volume de saída (%)." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_POWER_MANAGEMENT_SETTINGS, + "Gerenciamento de Energia" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_POWER_MANAGEMENT_SETTINGS, + "Altere as configurações de gerenciamento de energia." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SUSTAINED_PERFORMANCE_MODE, + "Modo de Desempenho Sustentado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_MPV_SUPPORT, + "Suporte de mpv" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_IDX, + "Índice" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_MATCH_IDX, + "Ver Coincidencia #" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_MATCH, + "Coindidir Endereço: %08X Mask: %02X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_MATCH, + "Criar Código de Coincidencia #" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_MATCH, + "Excluir Coincidencia #" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_BROWSE_MEMORY, + "Examinar Endereço: %08X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DESC, + "Descrição" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_STATE, + "Habilitar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_CODE, + "Código" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_HANDLER, + "Manipulador" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_MEMORY_SEARCH_SIZE, + "Tamanho da Memória de Pesquisa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_TYPE, + "Tipo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_VALUE, + "Valor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS, + "Endereço da Memória" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS_BIT_POSITION, + "Máscara do Endereço da Memória" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_TYPE, + "Vibrar Quando Memória" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_VALUE, + "Valor da Vibração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PORT, + "Porta de Vibração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_STRENGTH, + "Força Primária da Vibração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_DURATION, + "Duração (ms) da Vibração Primária" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_STRENGTH, + "Força Secundária da Vibração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_DURATION, + "Duração (ms) da Vibração Secundária" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_AFTER, + "Adicionar Nova Trapaça Depois Desta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BEFORE, + "Adicionar Nova Trapaça Antes Desta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_AFTER, + "Copiar Esta Trapaça Depois" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_BEFORE, + "Copiar Esta Trapaça Antes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE, + "Excluir Esta Trapaça" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_EMU, + "Emulador" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_RETRO, + "RetroArch" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_DISABLED, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_SET_TO_VALUE, + "Set To Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_INCREASE_VALUE, + "Increase By Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_DECREASE_VALUE, + "Decrease By Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_EQ, + "Run next cheat if value = memory" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_NEQ, + "Run next cheat if value != memory" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_LT, + "Run next cheat if value < memory" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_GT, + "Run next cheat if value > memory" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_DISABLED, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_CHANGES, + "Changes" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_DOES_NOT_CHANGE, + "Does Not Change" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_INCREASE, + "Increases" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_DECREASE, + "Decreases" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_EQ_VALUE, + "= Rumble Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_NEQ_VALUE, + "!= Rumble Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_LT_VALUE, + "< Rumble Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_GT_VALUE, + "> Rumble Value" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_1, + "1-bit, max value = 0x01" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_2, + "2-bit, max value = 0x03" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_4, + "4-bit, max value = 0x0F" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_8, + "8-bit, max value = 0xFF" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_16, + "16-bit, max value = 0xFFFF" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_32, + "32-bit, max value = 0xFFFFFFFF" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_0, + "1" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_1, + "2" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_2, + "3" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_3, + "4" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_4, + "5" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_5, + "6" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_6, + "7" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_7, + "8" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_8, + "9" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_9, + "10" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_10, + "11" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_11, + "12" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_12, + "13" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_13, + "14" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_14, + "15" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_15, + "16" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_PORT_16, + "All" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_CONT, + "Start or Continue Cheat Search" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_RESTART, + "Start or Restart Cheat Search" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EXACT, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LT, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GT, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQ, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GTE, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LTE, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_NEQ, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQPLUS, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQMINUS, + "Search Memory For Values" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_MATCHES, + "Add the %u Matches to Your List" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, + "View the List of %u Matches" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_CREATE_OPTION, + "Create Code From This Match" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_OPTION, + "Delete This Match" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_TOP, + "Add New Code to Top" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BOTTOM, + "Add New Code to Bottom" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_ALL, + "Delete All Codes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RELOAD_CHEATS, + "Reload Game-Specific Cheats" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EXACT_VAL, + "Equal to %u (%X)" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_LT_VAL, + "Less Than Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_GT_VAL, + "Greater Than Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_LTE_VAL, + "Less Than or Equal To Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_GTE_VAL, + "Greater Than or Equal To Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EQ_VAL, + "Equal to Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_NEQ_VAL, + "Not Equal to Before" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EQPLUS_VAL, + "Equal to Before+%u (%X)" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EQMINUS_VAL, + "Equal to Before-%u (%X)" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS, + "Start or Continue Cheat Search" + ) +MSG_HASH( + MSG_CHEAT_INIT_SUCCESS, + "Successfully started cheat search" + ) +MSG_HASH( + MSG_CHEAT_INIT_FAIL, + "Failed to start cheat search" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_NOT_INITIALIZED, + "Searching has not been initialized/started" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_FOUND_MATCHES, + "New match count = %u" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_BIG_ENDIAN, + "Big Endian" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS, + "Added %u matches" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL, + "Failed to add matches" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS, + "Created code from match" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_FAIL, + "Failed to create code" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS, + "Deleted match" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY, + "Not enough room. The total number of cheats you can have is 100." + ) +MSG_HASH( + MSG_CHEAT_ADD_TOP_SUCCESS, + "New cheat added to top of list." + ) +MSG_HASH( + MSG_CHEAT_ADD_BOTTOM_SUCCESS, + "New cheat added to bottom of list." + ) +MSG_HASH( + MSG_CHEAT_DELETE_ALL_INSTRUCTIONS, + "Press right five times to delete all cheats." + ) +MSG_HASH( + MSG_CHEAT_DELETE_ALL_SUCCESS, + "All cheats deleted." + ) +MSG_HASH( + MSG_CHEAT_ADD_BEFORE_SUCCESS, + "New cheat added before this one." + ) +MSG_HASH( + MSG_CHEAT_ADD_AFTER_SUCCESS, + "New cheat added after this one." + ) +MSG_HASH( + MSG_CHEAT_COPY_BEFORE_SUCCESS, + "Cheat copied before this one." + ) +MSG_HASH( + MSG_CHEAT_COPY_AFTER_SUCCESS, + "Cheat copied after this one." + ) +MSG_HASH( + MSG_CHEAT_DELETE_SUCCESS, + "Trapaça excluída." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PROGRESS, + "Progresso:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT, + "\"Todas Listas de Repr.\" Máx Entradas em Lista:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT, + "\"Todas Listas de Repr.\" Máx. Entradas em Grade:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES, + "Mostrar Arquivos e Pastas Ocultas:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST, + "Nova Lista de Reprodução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME, + "Por favor, insira o novo nome da lista de reprodução:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST, + "Excluir Lista de Reprodução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, + "Tem certeza de que deseja excluir a lista de reprodução \"%1\"?" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_QUESTION, + "Pergunta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, + "Não foi possível excluir o arquivo." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE, + "Não foi possível renomear o arquivo." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, + "Coletando lista de arquivos ..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, + "Adicionando arquivos à lista de reprodução..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY, + "Entrada da Lista de Reprodução" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_NAME, + "Nome:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_PATH, + "Caminho:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE, + "Núcleo:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, + "Banco de Dados:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, + "(usado para encontrar miniaturas)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM, + "Tem certeza de que deseja excluir o item? \"%1\"?" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS, + "Por favor, primeiro escolha uma única lista de reprodução." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DELETE, + "Excluir" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_ENTRY, + "Adicionar Entrada..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_FILES, + "Adicionar Arquivo(s)..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_FOLDER, + "Adicionar Pasta..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_EDIT, + "Editar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SELECT_FILES, + "Selecionar Arquivos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SELECT_FOLDER, + "Selecionar Pasta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY, + "Erro ao atualizar a entrada da lista de reprodução." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS, + "Por favor, preencha todos os campos requeridos." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY, + "Atualizar o RetroArch (nightly)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED, + "O RetroArch foi atualizado com sucesso. Por favor, reinicie o aplicativo para que as alterações entrem em vigor." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, + "Falha na atualização." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT_CONTRIBUTORS, + "Colaboradores" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, + "Shader atual" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, + "Move para Baixo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, + "Move para Cima" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOAD, + "Carregar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SAVE, + "Salvar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_REMOVE, + "Remover" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_APPLY, + "Aplicar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, + "Adicionar Passada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, + "Limpar Todas as Passadas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, + "Não há passada de shader" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_PASS, + "Restaurar Passada" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, + "Restaurar Todas as Passadas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, + "Restaurar Parâmetro" + ) From 6e9a8a9dd9fa17fcfa9deecf309ab5d413857007 Mon Sep 17 00:00:00 2001 From: altiereslima Date: Thu, 23 Aug 2018 13:23:03 -0300 Subject: [PATCH 136/182] fix --- intl/msg_hash_pt_br.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index 7bacfd3ce8..a527adc91c 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -6683,7 +6683,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MIDI_OUTPUT, - "Saída + "Saída" ) MSG_HASH( MENU_ENUM_SUBLABEL_MIDI_OUTPUT, From c39ce0e04beb3270a0133de7b66fc0cad705e0df Mon Sep 17 00:00:00 2001 From: Alfrix Date: Thu, 23 Aug 2018 16:41:07 -0300 Subject: [PATCH 137/182] Add Automatic theme It has been in the assets folder a long time by now --- intl/msg_hash_us.h | 4 ++++ menu/cbs/menu_cbs_get_value.c | 4 ++++ menu/drivers/xmb.c | 2 ++ menu/menu_driver.h | 1 + msg_hash.h | 1 + 5 files changed, 12 insertions(+) diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index ab19bb328c..31c4293bf1 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3294,6 +3294,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, "Dot-Art" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_AUTOMATIC, + "Automatic" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, "Menu Color Theme" diff --git a/menu/cbs/menu_cbs_get_value.c b/menu/cbs/menu_cbs_get_value.c index 066358dfed..4c9aaec8cd 100644 --- a/menu/cbs/menu_cbs_get_value.c +++ b/menu/cbs/menu_cbs_get_value.c @@ -976,6 +976,10 @@ static void menu_action_setting_disp_set_label_xmb_theme( strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM), len); break; + case XMB_ICON_THEME_AUTOMATIC: + strlcpy(s, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_AUTOMATIC), len); + break; } } diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index b3a8349f97..e2a2f2b3f4 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -449,6 +449,8 @@ const char* xmb_theme_ident(void) return "custom"; case XMB_ICON_THEME_MONOCHROME_INVERTED: return "monochrome-inverted"; + case XMB_ICON_THEME_AUTOMATIC: + return "automatic"; case XMB_ICON_THEME_MONOCHROME: default: break; diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 357f677b19..c802d8e812 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -278,6 +278,7 @@ enum xmb_icon_theme XMB_ICON_THEME_CUSTOM, XMB_ICON_THEME_RETROSYSTEM, XMB_ICON_THEME_MONOCHROME_INVERTED, + XMB_ICON_THEME_AUTOMATIC, XMB_ICON_THEME_LAST }; diff --git a/msg_hash.h b/msg_hash.h index 3c93035ef7..1ee633ba07 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -467,6 +467,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_SYSTEMATIC, MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_AUTOMATIC, MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LEGACY_RED, MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK_PURPLE, From 8dfeaba30b804187a154b850165c1bb89137d63c Mon Sep 17 00:00:00 2001 From: Alfrix Date: Fri, 24 Aug 2018 16:10:19 -0300 Subject: [PATCH 138/182] Add automatic and systematic to menu themes --- menu/drivers/xmb.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index e2a2f2b3f4..9b75562be8 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2279,12 +2279,10 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, /* Menu icons are here waiting for theme support*/ { settings_t *settings = config_get_ptr(); - if (settings->uints.menu_xmb_theme == XMB_ICON_THEME_MONOCHROME || - settings->uints.menu_xmb_theme == XMB_ICON_THEME_MONOCHROME_INVERTED || - settings->uints.menu_xmb_theme == XMB_ICON_THEME_CUSTOM || - settings->uints.menu_xmb_theme == XMB_ICON_THEME_DOTART || - settings->uints.menu_xmb_theme == XMB_ICON_THEME_RETROSYSTEM - ) + if (settings->uints.menu_xmb_theme != XMB_ICON_THEME_FLATUI || + settings->uints.menu_xmb_theme != XMB_ICON_THEME_NEOACTIVE || + settings->uints.menu_xmb_theme != XMB_ICON_THEME_RETROACTIVE || + settings->uints.menu_xmb_theme != XMB_ICON_THEME_PIXEL ) { switch (enum_idx) { From d8ea30881d8b89e582c1ba0118dbc3965d4d68d0 Mon Sep 17 00:00:00 2001 From: orbea Date: Fri, 24 Aug 2018 13:50:32 -0700 Subject: [PATCH 139/182] Default to gl instead of vulkan. If the video_driver is set incorrectly it will default to vulkan instead of gl. However its possible to have RetroArch built with vulkan even with no working vulkan drivers and this will cause a segfault. Defaulting to gl again should be a safer default which should crash for fewer users. Fixes https://github.com/libretro/RetroArch/issues/5568. --- gfx/video_driver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 3fa843eefa..37efe7b01a 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -262,12 +262,12 @@ struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = { }; static const video_driver_t *video_drivers[] = { -#ifdef HAVE_VULKAN - &video_vulkan, -#endif #ifdef HAVE_OPENGL &video_gl, #endif +#ifdef HAVE_VULKAN + &video_vulkan, +#endif #ifdef HAVE_METAL &video_metal, #endif From 260ce526c2fa56f5b297feb44f037d38847b5874 Mon Sep 17 00:00:00 2001 From: orbea Date: Fri, 24 Aug 2018 18:07:57 -0700 Subject: [PATCH 140/182] Fix segfaults when starting vulkan without a working vulkan driver. RetroArch will crash in several places when running vulkan in an environment that does not have working vulkan drivers. This should guard against those crashes and allow RetroArch to fail safely in those cases. --- gfx/common/vulkan_common.c | 5 ++++- gfx/drivers/vulkan.c | 11 ++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index a736a8c134..7c92a96643 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -1827,7 +1827,10 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk, VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; info.pfnCallback = vulkan_debug_cb; - vkCreateDebugReportCallbackEXT(vk->context.instance, &info, NULL, &vk->context.debug_callback); + + if (vk->context.instance) + vkCreateDebugReportCallbackEXT(vk->context.instance, &info, NULL, + &vk->context.debug_callback); } RARCH_LOG("[Vulkan]: Enabling Vulkan debug layers.\n"); #endif diff --git a/gfx/drivers/vulkan.c b/gfx/drivers/vulkan.c index f9fb7095c0..3d162d0118 100644 --- a/gfx/drivers/vulkan.c +++ b/gfx/drivers/vulkan.c @@ -744,6 +744,9 @@ static bool vulkan_init_default_filter_chain(vk_t *vk) memset(&info, 0, sizeof(info)); + if (!vk->context) + return false; + info.device = vk->context->device; info.gpu = vk->context->gpu; info.memory_properties = &vk->context->memory_properties; @@ -832,7 +835,7 @@ static bool vulkan_init_filter_chain(vk_t *vk) static void vulkan_init_resources(vk_t *vk) { - if (!vk) + if (!vk->context) return; vk->num_swapchain_images = vk->context->num_swapchain_images; @@ -855,6 +858,9 @@ static void vulkan_init_static_resources(vk_t *vk) VkPipelineCacheCreateInfo cache = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; + if (!vk->context) + return; + vkCreatePipelineCache(vk->context->device, &cache, NULL, &vk->pipelines.cache); @@ -2357,6 +2363,9 @@ static void vulkan_viewport_info(void *data, struct video_viewport *vp) video_driver_get_size(&width, &height); + if (!vk) + return; + /* Make sure we get the correct viewport. */ vulkan_set_viewport(vk, width, height, false, true); From e9e424ec828521d82e55e91b42c114741991666f Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 25 Aug 2018 01:00:18 -0400 Subject: [PATCH 141/182] Qt: add right-click option to download thumbnail for playlist entries --- Makefile.common | 3 +- griffin/griffin_cpp.cpp | 1 + intl/msg_hash_ja.h | 4 + intl/msg_hash_us.h | 4 + msg_hash.h | 2 + ui/drivers/qt/filedropwidget.cpp | 28 ++- ui/drivers/qt/playlist.cpp | 1 + ui/drivers/qt/shaderparamsdialog.cpp | 8 +- ui/drivers/qt/thumbnaildownload.cpp | 294 +++++++++++++++++++++++++++ ui/drivers/qt/ui_qt_window.cpp | 32 ++- ui/drivers/qt/updateretroarch.cpp | 1 + ui/drivers/ui_qt.h | 17 ++ 12 files changed, 387 insertions(+), 8 deletions(-) create mode 100644 ui/drivers/qt/thumbnaildownload.cpp diff --git a/Makefile.common b/Makefile.common index 7721c15c32..09ab22222d 100644 --- a/Makefile.common +++ b/Makefile.common @@ -346,7 +346,8 @@ OBJ += ui/drivers/ui_qt.o \ ui/drivers/qt/playlistentrydialog.o \ ui/drivers/qt/viewoptionsdialog.o \ ui/drivers/qt/playlist.o \ - ui/drivers/qt/updateretroarch.o + ui/drivers/qt/updateretroarch.o \ + ui/drivers/qt/thumbnaildownload.o MOC_HEADERS += ui/drivers/ui_qt.h \ ui/drivers/qt/ui_qt_load_core_window.h \ diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index a51280b7bf..5c75dfefdb 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -49,6 +49,7 @@ UI #include "../ui/drivers/qt/viewoptionsdialog.cpp" #include "../ui/drivers/qt/playlist.cpp" #include "../ui/drivers/qt/updateretroarch.cpp" +#include "../ui/drivers/qt/thumbnaildownload.cpp" #endif /*============================================================ diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 597e09af19..de56179467 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3788,3 +3788,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, "すべてのパスをリセット") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, "パラメータをリセット") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, + "サムネイルをダウンロード") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, + "他のダウンロードが実行中です。") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 31c4293bf1..675a4809eb 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -7386,3 +7386,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, "Reset Parameter" ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, + "Download thumbnail") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, + "A download is already in progress.") diff --git a/msg_hash.h b/msg_hash.h index 1ee633ba07..e87319e4de 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -2004,6 +2004,8 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_RESET_PASS, MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/filedropwidget.cpp b/ui/drivers/qt/filedropwidget.cpp index 0d3809b668..bf5fc32d64 100644 --- a/ui/drivers/qt/filedropwidget.cpp +++ b/ui/drivers/qt/filedropwidget.cpp @@ -81,6 +81,7 @@ void FileDropWidget::dropEvent(QDropEvent *event) void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) { QScopedPointer menu; + QScopedPointer downloadThumbnailAction; QScopedPointer addEntryAction; QScopedPointer addFilesAction; QScopedPointer addFolderAction; @@ -92,12 +93,14 @@ void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) menu.reset(new QMenu(this)); + downloadThumbnailAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL)), this)); addEntryAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_ENTRY)), this)); addFilesAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_FILES)), this)); addFolderAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_FOLDER)), this)); editAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_EDIT)), this)); deleteAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DELETE)), this)); + menu->addAction(downloadThumbnailAction.data()); menu->addAction(addEntryAction.data()); menu->addAction(addFilesAction.data()); menu->addAction(addFolderAction.data()); @@ -113,7 +116,30 @@ void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) if (!selectedAction) return; - if (selectedAction == addFilesAction.data()) + if (selectedAction == downloadThumbnailAction.data()) + { + QHash hash = getCurrentContentHash(); + QString system = QFileInfo(getCurrentPlaylistPath()).completeBaseName(); + QString path = hash.value("label"); + + if (!path.isEmpty()) + { + QString title = QFileInfo(path).completeBaseName(); + + if (m_pendingThumbnailDownloadTypes.isEmpty()) + { + m_pendingThumbnailDownloadTypes.append(THUMBNAIL_BOXART); + m_pendingThumbnailDownloadTypes.append(THUMBNAIL_SCREENSHOT); + m_pendingThumbnailDownloadTypes.append(THUMBNAIL_TITLE); + downloadThumbnail(system, title); + } + else + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + } + } + } + else if (selectedAction == addFilesAction.data()) { QStringList filePaths = QFileDialog::getOpenFileNames(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_FILES)); diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp index f2f1e4ef86..7113500f3d 100644 --- a/ui/drivers/qt/playlist.cpp +++ b/ui/drivers/qt/playlist.cpp @@ -992,6 +992,7 @@ void MainWindow::addPlaylistHashToGrid(const QVector > & item->widget->setLayout(new QVBoxLayout()); item->widget->setObjectName("thumbnailWidget"); item->widget->setProperty("hash", QVariant::fromValue >(hash)); + item->widget->setProperty("image_path", imagePath); connect(item->widget, SIGNAL(mouseDoubleClicked()), this, SLOT(onGridItemDoubleClicked())); connect(item->widget, SIGNAL(mousePressed()), this, SLOT(onGridItemClicked())); diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 2ed8ecdaf4..cffcd85498 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -1339,7 +1339,7 @@ void ShaderParamsDialog::onShaderParamCheckBoxClicked() struct video_shader_parameter *param = NULL; int i; - for (i = 0; i < video_shader->num_parameters; i++) + for (i = 0; i < static_cast(video_shader->num_parameters); i++) { QString id = video_shader->parameters[i].id; @@ -1399,7 +1399,7 @@ void ShaderParamsDialog::onShaderParamSliderValueChanged(int) struct video_shader_parameter *param = NULL; int i; - for (i = 0; i < video_shader->num_parameters; i++) + for (i = 0; i < static_cast(video_shader->num_parameters); i++) { QString id = video_shader->parameters[i].id; @@ -1500,7 +1500,7 @@ void ShaderParamsDialog::onShaderParamSpinBoxValueChanged(int value) struct video_shader_parameter *param = NULL; int i; - for (i = 0; i < video_shader->num_parameters; i++) + for (i = 0; i < static_cast(video_shader->num_parameters); i++) { QString id = video_shader->parameters[i].id; @@ -1580,7 +1580,7 @@ void ShaderParamsDialog::onShaderParamDoubleSpinBoxValueChanged(double value) struct video_shader_parameter *param = NULL; int i; - for (i = 0; i < video_shader->num_parameters; i++) + for (i = 0; i < static_cast(video_shader->num_parameters); i++) { QString id = video_shader->parameters[i].id; diff --git a/ui/drivers/qt/thumbnaildownload.cpp b/ui/drivers/qt/thumbnaildownload.cpp new file mode 100644 index 0000000000..4094cd495d --- /dev/null +++ b/ui/drivers/qt/thumbnaildownload.cpp @@ -0,0 +1,294 @@ +#include +#include +#include + +#include "../ui_qt.h" + +extern "C" { +#include +#include +#include +#include "../../../tasks/tasks_internal.h" +#include "../../../verbosity.h" +#include "../../../config.def.h" +#include "../../../configuration.h" +#include "../../../version.h" +} + +#define USER_AGENT "RetroArch-WIMP/" PACKAGE_VERSION +#define PARTIAL_EXTENSION ".partial" +#define TEMP_EXTENSION ".tmp" +#define THUMBNAIL_URL_HEADER "https://github.com/libretro-thumbnails/" +#define THUMBNAIL_URL_BRANCH "/blob/master/" +#define THUMBNAIL_IMAGE_EXTENSION ".png" +#define THUMBNAIL_URL_FOOTER THUMBNAIL_IMAGE_EXTENSION "?raw=true" + +void MainWindow::onThumbnailDownloadNetworkError(QNetworkReply::NetworkError code) +{ + QNetworkReply *reply = m_thumbnailDownloadReply.data(); + QByteArray errorStringArray; + const char *errorStringData = NULL; + + m_thumbnailDownloadProgressDialog->cancel(); + + if (!reply) + return; + + errorStringArray = reply->errorString().toUtf8(); + errorStringData = errorStringArray.constData(); + + RARCH_ERR("[Qt]: Network error code %d received: %s\n", code, errorStringData); + + /* Deleting the reply here seems to cause a strange heap-use-after-free crash. */ + /* + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + */ +} + +void MainWindow::onThumbnailDownloadNetworkSslErrors(const QList &errors) +{ + QNetworkReply *reply = m_thumbnailDownloadReply.data(); + int i; + + if (!reply) + return; + + for (i = 0; i < errors.count(); i++) + { + const QSslError &error = errors.at(i); + QString string = QString("Ignoring SSL error code ") + QString::number(error.error()) + ": " + error.errorString(); + QByteArray stringArray = string.toUtf8(); + const char *stringData = stringArray.constData(); + RARCH_ERR("[Qt]: %s\n", stringData); + } + + /* ignore all SSL errors for now, like self-signed, expired etc. */ + reply->ignoreSslErrors(); +} + +void MainWindow::onThumbnailDownloadCanceled() +{ + m_thumbnailDownloadProgressDialog->cancel(); +} + +void MainWindow::onThumbnailDownloadFinished() +{ + QString system; + QString title; + QString downloadType; + QNetworkReply *reply = m_thumbnailDownloadReply.data(); + QNetworkReply::NetworkError error; + int code; + + m_thumbnailDownloadProgressDialog->cancel(); + + /* At least on Linux, the progress dialog will refuse to hide itself and will stay on screen in a corrupted way if we happen to show an error message in this function. processEvents() will sometimes fix it, other times not... seems random. */ + qApp->processEvents(); + + if (!reply) + return; + + system = reply->property("system").toString(); + title = reply->property("title").toString(); + downloadType = reply->property("download_type").toString(); + + error = reply->error(); + code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (m_thumbnailDownloadFile.isOpen()) + m_thumbnailDownloadFile.close(); + + if (code != 200) + { + QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + + if (!redirectUrl.isEmpty()) + { + QByteArray redirectUrlArray = redirectUrl.toString().toUtf8(); + const char *redirectUrlData = redirectUrlArray.constData(); + + m_pendingThumbnailDownloadTypes.prepend(downloadType); + + RARCH_LOG("[Qt]: Thumbnail download got redirect with HTTP code %d: %s\n", code, redirectUrlData); + + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + + downloadThumbnail(system, title, redirectUrl); + + return; + } + else + { + /*emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": HTTP Code " + QString::number(code));*/ + + RARCH_ERR("[Qt]: Thumbnail download failed with HTTP status code: %d\n", code); + + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + + if (!m_pendingThumbnailDownloadTypes.isEmpty()) + downloadThumbnail(system, title); + + return; + } + } + + if (error == QNetworkReply::NoError) + { + int index = m_thumbnailDownloadFile.fileName().lastIndexOf(PARTIAL_EXTENSION); + QString newFileName = m_thumbnailDownloadFile.fileName().left(index); + QFile newFile(newFileName); + + /* rename() requires the old file to be deleted first if it exists */ + if (newFile.exists() && !newFile.remove()) + RARCH_ERR("[Qt]: Thumbnail download finished, but old file could not be deleted.\n"); + else + { + if (m_thumbnailDownloadFile.rename(newFileName)) + { + RARCH_LOG("[Qt]: Thumbnail download finished successfully.\n"); + /* reload thumbnail image */ + emit itemChanged(); + } + else + { + RARCH_ERR("[Qt]: Thumbnail download finished, but temp file could not be renamed.\n"); + emit showErrorMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE)); + } + } + } + else + { + QByteArray errorArray = reply->errorString().toUtf8(); + const char *errorData = errorArray.constData(); + + RARCH_ERR("[Qt]: Thumbnail download ended prematurely: %s\n", errorData); + emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": Code " + QString::number(code) + ": " + errorData); + } + + reply->disconnect(); + reply->close(); + reply->deleteLater(); + + if (!m_pendingThumbnailDownloadTypes.isEmpty()) + emit gotThumbnailDownload(system, title); +} + +void MainWindow::onDownloadThumbnail(QString system, QString title) +{ + downloadThumbnail(system, title); +} + +void MainWindow::onThumbnailDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + QNetworkReply *reply = m_thumbnailDownloadReply.data(); + int progress = (bytesReceived / (float)bytesTotal) * 100.0f; + + if (!reply) + return; + + m_thumbnailDownloadProgressDialog->setValue(progress); +} + +void MainWindow::onThumbnailDownloadReadyRead() +{ + QNetworkReply *reply = m_thumbnailDownloadReply.data(); + + if (!reply) + return; + + m_thumbnailDownloadFile.write(reply->readAll()); +} + +void MainWindow::downloadThumbnail(QString system, QString title, QUrl url) +{ + QString systemUnderscore = system; + QString urlString; + QNetworkReply *reply = NULL; + QNetworkRequest request; + QByteArray urlArray; + QString downloadType; + settings_t *settings = config_get_ptr(); + const char *urlData = NULL; + + if (!settings || m_pendingThumbnailDownloadTypes.isEmpty()) + return; + + downloadType = m_pendingThumbnailDownloadTypes.takeFirst(); + + systemUnderscore = systemUnderscore.replace(" ", "_"); + + urlString = QString(THUMBNAIL_URL_HEADER) + systemUnderscore + THUMBNAIL_URL_BRANCH + downloadType + "/" + title + THUMBNAIL_URL_FOOTER; + + if (url.isEmpty()) + url = urlString; + + request.setUrl(url); + + urlArray = url.toString().toUtf8(); + urlData = urlArray.constData(); + + if (m_thumbnailDownloadFile.isOpen()) + { + RARCH_ERR("[Qt]: File is already open.\n"); + return; + } + else + { + QString dirString = QString(settings->paths.directory_thumbnails) + "/" + system + "/" + downloadType; + QString fileName = dirString + "/" + title + THUMBNAIL_IMAGE_EXTENSION + PARTIAL_EXTENSION; + QDir dir; + QByteArray fileNameArray = fileName.toUtf8(); + const char *fileNameData = fileNameArray.constData(); + + dir.mkpath(dirString); + + m_thumbnailDownloadFile.setFileName(fileName); + + if (!m_thumbnailDownloadFile.open(QIODevice::WriteOnly)) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Could not open file for writing: %s\n", fileNameData); + return; + } + } + + RARCH_LOG("[Qt]: Starting thumbnail download...\n"); + RARCH_LOG("[Qt]: Downloading URL %s\n", urlData); + + request.setHeader(QNetworkRequest::UserAgentHeader, USER_AGENT); + + m_thumbnailDownloadProgressDialog->setWindowModality(Qt::NonModal); + m_thumbnailDownloadProgressDialog->setMinimumDuration(0); + m_thumbnailDownloadProgressDialog->setRange(0, 100); + m_thumbnailDownloadProgressDialog->setAutoClose(true); + m_thumbnailDownloadProgressDialog->setAutoReset(true); + m_thumbnailDownloadProgressDialog->setValue(0); + m_thumbnailDownloadProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_DOWNLOADING)) + "..."); + m_thumbnailDownloadProgressDialog->setCancelButtonText(tr("Cancel")); + m_thumbnailDownloadProgressDialog->show(); + + m_thumbnailDownloadReply = m_networkManager->get(request); + + reply = m_thumbnailDownloadReply.data(); + reply->setProperty("system", system); + reply->setProperty("title", title); + reply->setProperty("download_type", downloadType); + + /* make sure any previous connection is removed first */ + disconnect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); + disconnect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailDownloadProgressDialog, SLOT(cancel())); + connect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); + connect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailDownloadProgressDialog, SLOT(cancel())); + + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onThumbnailDownloadNetworkError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(sslErrors(const QList&)), this, SLOT(onThumbnailDownloadNetworkSslErrors(const QList&))); + connect(reply, SIGNAL(finished()), this, SLOT(onThumbnailDownloadFinished())); + connect(reply, SIGNAL(readyRead()), this, SLOT(onThumbnailDownloadReadyRead())); + connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onThumbnailDownloadProgress(qint64, qint64))); +} diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 5e0f65693a..78ccdd45f7 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -85,8 +85,6 @@ extern "C" { #endif #define GENERIC_FOLDER_ICON "/xmb/dot-art/png/folder.png" -#define THUMBNAIL_SCREENSHOT "Named_Snaps" -#define THUMBNAIL_TITLE "Named_Titles" #define HIRAGANA_START 0x3041U #define HIRAGANA_END 0x3096U #define KATAKANA_START 0x30A1U @@ -318,6 +316,9 @@ MainWindow::MainWindow(QWidget *parent) : ,m_updateProgressDialog(new QProgressDialog()) ,m_updateFile() ,m_updateReply() + ,m_thumbnailDownloadProgressDialog(new QProgressDialog()) + ,m_thumbnailDownloadReply() + ,m_pendingThumbnailDownloadTypes() { settings_t *settings = config_get_ptr(); QDir playlistDir(settings->paths.directory_playlist); @@ -338,6 +339,7 @@ MainWindow::MainWindow(QWidget *parent) : qRegisterMetaType >("ThumbnailWidget"); m_updateProgressDialog->cancel(); + m_thumbnailDownloadProgressDialog->cancel(); m_gridProgressWidget = new QWidget(); gridProgressLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PROGRESS), m_gridProgressWidget); @@ -535,6 +537,9 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_gridLayoutWidget, SIGNAL(filesDropped(QStringList)), this, SLOT(onPlaylistFilesDropped(QStringList))); connect(m_gridLayoutWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onFileDropWidgetContextMenuRequested(const QPoint&))); + connect(this, SIGNAL(itemChanged()), this, SLOT(onItemChanged())); + connect(this, SIGNAL(gotThumbnailDownload(QString,QString)), this, SLOT(onDownloadThumbnail(QString,QString))); + /* make sure these use an auto connection so it will be queued if called from a different thread (some facilities in RA log messages from other threads) */ connect(this, SIGNAL(gotLogMessage(const QString&)), this, SLOT(onGotLogMessage(const QString&)), Qt::AutoConnection); connect(this, SIGNAL(gotStatusMessage(QString,unsigned,unsigned,bool)), this, SLOT(onGotStatusMessage(QString,unsigned,unsigned,bool)), Qt::AutoConnection); @@ -581,6 +586,29 @@ MainWindow::~MainWindow() removeGridItems(); } +void MainWindow::onItemChanged() +{ + ViewType viewType = getCurrentViewType(); + + currentItemChanged(getCurrentContentHash()); + + if (viewType == VIEW_TYPE_ICONS) + { + int i; + + for (i = 0; i < m_gridItems.count(); i++) + { + const QPointer &item = m_gridItems.at(i); + + if (item->widget == m_currentGridWidget) + { + loadImageDeferred(item.data(), m_currentGridWidget->property("image_path").toString()); + break; + } + } + } +} + QString MainWindow::getSpecialPlaylistPath(SpecialPlaylist playlist) { switch (playlist) diff --git a/ui/drivers/qt/updateretroarch.cpp b/ui/drivers/qt/updateretroarch.cpp index da67edb862..454de2eb7c 100644 --- a/ui/drivers/qt/updateretroarch.cpp +++ b/ui/drivers/qt/updateretroarch.cpp @@ -338,6 +338,7 @@ void MainWindow::updateRetroArchNightly() m_updateProgressDialog->show(); m_updateReply = m_networkManager->get(request); + reply = m_updateReply.data(); /* make sure any previous connection is removed first */ diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index f3703a499d..69d8b899eb 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -48,6 +48,8 @@ extern "C" { #define ALL_PLAYLISTS_TOKEN "|||ALL|||" #define ICON_PATH "/xmb/dot-art/png/" #define THUMBNAIL_BOXART "Named_Boxarts" +#define THUMBNAIL_SCREENSHOT "Named_Snaps" +#define THUMBNAIL_TITLE "Named_Titles" class QApplication; class QCloseEvent; @@ -295,6 +297,8 @@ signals: void showErrorMessageDeferred(QString msg); void showInfoMessageDeferred(QString msg); void extractArchiveDeferred(QString path); + void itemChanged(); + void gotThumbnailDownload(QString system, QString title); public slots: void onBrowserDownloadsClicked(); @@ -333,6 +337,7 @@ public slots: void updateRetroArchNightly(); void onUpdateRetroArchFinished(bool success); void deferReloadShaderParams(); + void downloadThumbnail(QString system, QString title, QUrl url = QUrl()); private slots: void onLoadCoreClicked(const QStringList &extensionFilters = QStringList()); @@ -374,6 +379,14 @@ private slots: void onShowErrorMessage(QString msg); void onShowInfoMessage(QString msg); void onContributorsClicked(); + void onThumbnailDownloadNetworkError(QNetworkReply::NetworkError code); + void onThumbnailDownloadNetworkSslErrors(const QList &errors); + void onThumbnailDownloadFinished(); + void onThumbnailDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void onThumbnailDownloadReadyRead(); + void onThumbnailDownloadCanceled(); + void onItemChanged(); + void onDownloadThumbnail(QString system, QString title); int onExtractArchive(QString path); private: @@ -452,6 +465,10 @@ private: QProgressDialog *m_updateProgressDialog; QFile m_updateFile; QPointer m_updateReply; + QProgressDialog *m_thumbnailDownloadProgressDialog; + QFile m_thumbnailDownloadFile; + QPointer m_thumbnailDownloadReply; + QStringList m_pendingThumbnailDownloadTypes; protected: void closeEvent(QCloseEvent *event); From 3c6e42ccf61d52544d503b79a1982634cfa10a59 Mon Sep 17 00:00:00 2001 From: orbea Date: Sat, 25 Aug 2018 06:29:44 -0700 Subject: [PATCH 142/182] Silence -Wunknown-warning-option warnings with clang. When building CXX code with clang it will print many warnings. warning: unknown warning option '-Wno-maybe-uninitialized'; did you mean '-Wno-uninitialized'? [-Wunknown-warning-option] However removing this flag does not introduce any warnings so it should be safe to remove. --- Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.common b/Makefile.common index 7721c15c32..5492a91cc1 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1141,7 +1141,7 @@ ifeq ($(HAVE_VULKAN), 1) CXXFLAGS += -fpermissive endif - CXXFLAGS += -Wno-switch -Wno-sign-compare -fno-strict-aliasing -Wno-maybe-uninitialized -Wno-reorder -Wno-parentheses + CXXFLAGS += -Wno-switch -Wno-sign-compare -fno-strict-aliasing -Wno-reorder -Wno-parentheses OBJ += gfx/drivers/vulkan.o \ gfx/common/vulkan_common.o \ From 3d056bc8c450e323fad12d0aa4acb887f5a93096 Mon Sep 17 00:00:00 2001 From: altiereslima Date: Sat, 25 Aug 2018 16:24:17 -0300 Subject: [PATCH 143/182] Update brazilian portuguese translation --- intl/msg_hash_pt_br.h | 150 +++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index a527adc91c..4b9758d9d1 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -6719,7 +6719,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_MATCH_IDX, - "Ver Coincidencia #" + "Ver Coincidência #" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_MATCH, @@ -6727,11 +6727,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_COPY_MATCH, - "Criar Código de Coincidencia #" + "Criar Código de Coincidência #" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_MATCH, - "Excluir Coincidencia #" + "Excluir Coincidência #" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_BROWSE_MEMORY, @@ -6831,95 +6831,95 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_TYPE_DISABLED, - "" + "" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_TYPE_SET_TO_VALUE, - "Set To Value" + "Ajustar Valor" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_TYPE_INCREASE_VALUE, - "Increase By Value" + "Aumentar por Valor" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_TYPE_DECREASE_VALUE, - "Decrease By Value" + "Diminuir por Valor" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_EQ, - "Run next cheat if value = memory" + "Executar próxima trapaça se valor for igual à memória" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_NEQ, - "Run next cheat if value != memory" + "Executar próxima trapaça se valor for diferente da memória" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_LT, - "Run next cheat if value < memory" + "Executar próxima trapaça se valor for menor que a memória" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_GT, - "Run next cheat if value > memory" + "Executar próxima trapaça se valor for maior que a memória" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_DISABLED, - "" + "" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_CHANGES, - "Changes" + "Alterações" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_DOES_NOT_CHANGE, - "Does Not Change" + "Não Altera" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_INCREASE, - "Increases" + "Aumenta" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_DECREASE, - "Decreases" + "Diminui" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_EQ_VALUE, - "= Rumble Value" + "Igual Ao Valor da Vibração" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_NEQ_VALUE, - "!= Rumble Value" + "Diferente Ao Valor da Vibração" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_LT_VALUE, - "< Rumble Value" + "Menor Ao Valor da Vibração" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_GT_VALUE, - "> Rumble Value" + "Maior Ao Valor da Vibração" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_1, - "1-bit, max value = 0x01" + "1-bit, valor máx. = 0x01" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_2, - "2-bit, max value = 0x03" + "2-bit, valor máx. = 0x03" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_4, - "4-bit, max value = 0x0F" + "4-bit, valor máx. = 0x0F" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_8, - "8-bit, max value = 0xFF" + "8-bit, valor máx. = 0xFF" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_16, - "16-bit, max value = 0xFFFF" + "16-bit, valor máx. = 0xFFFF" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_32, - "32-bit, max value = 0xFFFFFFFF" + "32-bit, valor máx. = 0xFFFFFFFF" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_PORT_0, @@ -6991,135 +6991,135 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_CONT, - "Start or Continue Cheat Search" + "Iniciar ou Continuar a Pesquisa de Trapaças" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_RESTART, - "Start or Restart Cheat Search" + "Iniciar ou Reiniciar a Pesquisa de Trapaças" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EXACT, - "Search Memory For Values" + "Pesquisar Memória por Valores" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LT, - "Search Memory For Values" + "Pesquisar Memória por Valores" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GT, - "Search Memory For Values" + "Pesquisar Memória por Valores" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQ, - "Search Memory For Values" + "Pesquisar Memória por Valores" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GTE, - "Search Memory For Values" + "Pesquisar Memória por Valores" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LTE, - "Search Memory For Values" + "Pesquisar Memória por Valores" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_NEQ, - "Search Memory For Values" + "Pesquisar Memória por Valores ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQPLUS, - "Search Memory For Values" + "Pesquisar Memória por Valores" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQMINUS, - "Search Memory For Values" + "Pesquisar Memória por Valores" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_ADD_MATCHES, - "Add the %u Matches to Your List" + "Adicionar as %u Coincidências para Sua Lista" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, - "View the List of %u Matches" + "Ver Lista de %u Coincidências" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_CREATE_OPTION, - "Create Code From This Match" + "Criar Código Desta CoincidênciaCoincidência" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_OPTION, - "Delete This Match" + "Excluir Esta Coincidência" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_TOP, - "Add New Code to Top" + "Adicionar Novo Código no Início" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BOTTOM, - "Add New Code to Bottom" + "Adicionar Novo Código no Final" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_ALL, - "Delete All Codes" + "Excluir Todas as Trapaças" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_RELOAD_CHEATS, - "Reload Game-Specific Cheats" + "Recarregar Trapaças Específicas do Jogo" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_EXACT_VAL, - "Equal to %u (%X)" + "Igual a %u (%X)" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_LT_VAL, - "Less Than Before" + "Menos do que Antes" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_GT_VAL, - "Greater Than Before" + "Maior que Antes" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_LTE_VAL, - "Less Than or Equal To Before" + "Menos ou Igual a Antes" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_GTE_VAL, - "Greater Than or Equal To Before" + "Maior ou Igual a Antes" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_EQ_VAL, - "Equal to Before" + "Igual a Antes" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_NEQ_VAL, - "Not Equal to Before" + "Diferente a Antes" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_EQPLUS_VAL, - "Equal to Before+%u (%X)" + "Igual a Depois+%u (%X)" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_EQMINUS_VAL, - "Equal to Before-%u (%X)" + "Igual a Antes-%u (%X)" ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS, - "Start or Continue Cheat Search" + "Iniciar ou Continuar Pesquisa de Trapaças" ) MSG_HASH( MSG_CHEAT_INIT_SUCCESS, - "Successfully started cheat search" + "Pesquisa de trapaças iniciada corretamente" ) MSG_HASH( MSG_CHEAT_INIT_FAIL, - "Failed to start cheat search" + "Falha ao iniciar a pesquisa de trapaças" ) MSG_HASH( MSG_CHEAT_SEARCH_NOT_INITIALIZED, - "Searching has not been initialized/started" + "A pesquisa não foi iniciada" ) MSG_HASH( MSG_CHEAT_SEARCH_FOUND_MATCHES, - "New match count = %u" + "Número de coincidências = %u" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_BIG_ENDIAN, @@ -7127,59 +7127,59 @@ MSG_HASH( ) MSG_HASH( MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS, - "Added %u matches" + "Adicionadas %u coincidências" ) MSG_HASH( MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL, - "Failed to add matches" + "Falha ao adicionar coincidências" ) MSG_HASH( MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS, - "Created code from match" + "Código criado da coincidência" ) MSG_HASH( MSG_CHEAT_SEARCH_ADD_MATCH_FAIL, - "Failed to create code" + "Falha ao criar o código" ) MSG_HASH( MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS, - "Deleted match" + "Excluir coincidência" ) MSG_HASH( MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY, - "Not enough room. The total number of cheats you can have is 100." + "Não há espaço suficiente. O máximo é 100 trapaças" ) MSG_HASH( MSG_CHEAT_ADD_TOP_SUCCESS, - "New cheat added to top of list." + "Nova trapaça adicionada ao início da lista." ) MSG_HASH( MSG_CHEAT_ADD_BOTTOM_SUCCESS, - "New cheat added to bottom of list." + "Nova trapaça adicionada ao final da lista." ) MSG_HASH( MSG_CHEAT_DELETE_ALL_INSTRUCTIONS, - "Press right five times to delete all cheats." + "Pressione direita cinco vezes para excluir todas as trapaças." ) MSG_HASH( MSG_CHEAT_DELETE_ALL_SUCCESS, - "All cheats deleted." + "Todas as trapaças foram excluídas." ) MSG_HASH( MSG_CHEAT_ADD_BEFORE_SUCCESS, - "New cheat added before this one." + "Nova trapaça adicionada antes deste." ) MSG_HASH( MSG_CHEAT_ADD_AFTER_SUCCESS, - "New cheat added after this one." + "Nova trapaça adicionada depois deste." ) MSG_HASH( MSG_CHEAT_COPY_BEFORE_SUCCESS, - "Cheat copied before this one." + "Trapaça copiada antes deste." ) MSG_HASH( MSG_CHEAT_COPY_AFTER_SUCCESS, - "Cheat copied after this one." + "Trapaça copiada depois deste." ) MSG_HASH( MSG_CHEAT_DELETE_SUCCESS, @@ -7191,11 +7191,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT, - "\"Todas Listas de Repr.\" Máx Entradas em Lista:" + "\"Todas as Listas de Repr.\" Máx. Entradas em Lista:" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT, - "\"Todas Listas de Repr.\" Máx. Entradas em Grade:" + "\"Todas as Listas de Repr.\" Máx. Entradas em Grade:" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES, From 8c7526d8ef064f5b7cac71e30d33e516767ad44b Mon Sep 17 00:00:00 2001 From: altiereslima Date: Sat, 25 Aug 2018 16:38:26 -0300 Subject: [PATCH 144/182] como sempre... --- intl/msg_hash_pt_br.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index 4b9758d9d1..e939534814 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -7023,7 +7023,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_NEQ, - "Pesquisar Memória por Valores + "Pesquisar Memória por Valores" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQPLUS, From 821462409e4916b194979262bf2e41d59dd3a094 Mon Sep 17 00:00:00 2001 From: Dwedit Date: Sun, 26 Aug 2018 00:22:19 -0500 Subject: [PATCH 145/182] Deterministic input for RunAhead, guaranteed to match the last polled input. --- runahead/dirty_input.c | 2 +- runahead/dirty_input.h | 2 ++ runahead/run_ahead.c | 49 ++++++++++++++++++++++++++++++++++----- runahead/secondary_core.c | 24 ++++++++++++++++++- runahead/secondary_core.h | 2 +- 5 files changed, 70 insertions(+), 9 deletions(-) diff --git a/runahead/dirty_input.c b/runahead/dirty_input.c index 965d932531..7ff4bfee37 100644 --- a/runahead/dirty_input.c +++ b/runahead/dirty_input.c @@ -80,7 +80,7 @@ static void input_state_set_last(unsigned port, unsigned device, element->state[id] = value; } -static int16_t input_state_get_last(unsigned port, +int16_t input_state_get_last(unsigned port, unsigned device, unsigned index, unsigned id) { unsigned i; diff --git a/runahead/dirty_input.h b/runahead/dirty_input.h index 12623d2b02..fc76e8b0bc 100644 --- a/runahead/dirty_input.h +++ b/runahead/dirty_input.h @@ -9,6 +9,8 @@ RETRO_BEGIN_DECLS extern bool input_is_dirty; void add_input_state_hook(void); void remove_input_state_hook(void); +int16_t input_state_get_last(unsigned port, + unsigned device, unsigned index, unsigned id); RETRO_END_DECLS diff --git a/runahead/run_ahead.c b/runahead/run_ahead.c index 77b6117c07..f5ce38b51c 100644 --- a/runahead/run_ahead.c +++ b/runahead/run_ahead.c @@ -30,6 +30,8 @@ static void unset_fast_savestate(void); static void set_hard_disable_audio(void); static void unset_hard_disable_audio(void); +static bool core_run_use_last_input(void); + static size_t runahead_save_state_size = 0; static bool runahead_save_state_size_known = false; @@ -174,13 +176,19 @@ static void runahead_clear_variables(void) runahead_last_frame_count = 0; } +static uint64_t runahead_get_frame_count() +{ + bool is_alive, is_focused = false; + uint64_t frame_count = 0; + video_driver_get_status(&frame_count, &is_alive, &is_focused); + return frame_count; +} + + static void runahead_check_for_gui(void) { /* Hack: If we were in the GUI, force a resync. */ - bool is_alive, is_focused = false; - uint64_t frame_count = 0; - - video_driver_get_status(&frame_count, &is_alive, &is_focused); + uint64_t frame_count = runahead_get_frame_count(); if (frame_count != runahead_last_frame_count + 1) runahead_force_input_dirty = true; @@ -241,7 +249,7 @@ void run_ahead(int runahead_count, bool useSecondary) if (frame_number == 0) core_run(); else - core_run_no_input_polling(); + core_run_use_last_input(); if (suspended_frame) { @@ -418,7 +426,7 @@ static bool runahead_load_state_secondary(void) static bool runahead_run_secondary(void) { - if (!secondary_core_run_no_input_polling()) + if (!secondary_core_run_use_last_input()) { runahead_secondary_core_available = false; return false; @@ -489,3 +497,32 @@ static void unset_hard_disable_audio(void) { hard_disable_audio = false; } + +static void runahead_input_poll_null(void) +{ +} + +static bool core_run_use_last_input(void) +{ + extern struct retro_callbacks retro_ctx; + extern struct retro_core_t current_core; + + retro_input_poll_t old_poll_function = retro_ctx.poll_cb; + retro_input_state_t old_input_function = retro_ctx.state_cb; + + retro_ctx.poll_cb = runahead_input_poll_null; + retro_ctx.state_cb = input_state_get_last; + + current_core.retro_set_input_poll(retro_ctx.poll_cb); + current_core.retro_set_input_state(retro_ctx.state_cb); + + current_core.retro_run(); + + retro_ctx.poll_cb = old_poll_function; + retro_ctx.state_cb = old_input_function; + + current_core.retro_set_input_poll(retro_ctx.poll_cb); + current_core.retro_set_input_state(retro_ctx.state_cb); + + return true; +} diff --git a/runahead/secondary_core.c b/runahead/secondary_core.c index 9d0d67de4b..7d50a2d9ba 100644 --- a/runahead/secondary_core.c +++ b/runahead/secondary_core.c @@ -23,6 +23,7 @@ #include "../content.h" #include "secondary_core.h" +#include "dirty_input.h" static int port_map[16]; @@ -304,11 +305,32 @@ void secondary_core_set_variable_update(void) has_variable_update = true; } -bool secondary_core_run_no_input_polling(void) +static void secondary_core_input_poll_null(void) +{ + +} + +bool secondary_core_run_use_last_input(void) { if (secondary_core_ensure_exists()) { + retro_input_poll_t old_poll_function = secondary_callbacks.poll_cb; + retro_input_state_t old_input_function = secondary_callbacks.state_cb; + + secondary_callbacks.poll_cb = secondary_core_input_poll_null; + secondary_callbacks.state_cb = input_state_get_last; + + secondary_core.retro_set_input_poll(secondary_callbacks.poll_cb); + secondary_core.retro_set_input_state(secondary_callbacks.state_cb); + secondary_core.retro_run(); + + secondary_callbacks.poll_cb = old_poll_function; + secondary_callbacks.state_cb = old_input_function; + + secondary_core.retro_set_input_poll(secondary_callbacks.poll_cb); + secondary_core.retro_set_input_state(secondary_callbacks.state_cb); + return true; } return false; diff --git a/runahead/secondary_core.h b/runahead/secondary_core.h index d4da77cdec..9a6ead0b7c 100644 --- a/runahead/secondary_core.h +++ b/runahead/secondary_core.h @@ -10,7 +10,7 @@ RETRO_BEGIN_DECLS -bool secondary_core_run_no_input_polling(void); +bool secondary_core_run_use_last_input(void); bool secondary_core_deserialize(const void *buffer, int size); bool secondary_core_ensure_exists(void); void secondary_core_destroy(void); From 78f5aba04bed8e5df853326b4ad29b5c74d38f04 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 26 Aug 2018 10:40:08 -0400 Subject: [PATCH 146/182] Qt: fix filename used for thumbnail download --- ui/drivers/qt/filedropwidget.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui/drivers/qt/filedropwidget.cpp b/ui/drivers/qt/filedropwidget.cpp index bf5fc32d64..3e5b1bf13c 100644 --- a/ui/drivers/qt/filedropwidget.cpp +++ b/ui/drivers/qt/filedropwidget.cpp @@ -120,12 +120,10 @@ void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) { QHash hash = getCurrentContentHash(); QString system = QFileInfo(getCurrentPlaylistPath()).completeBaseName(); - QString path = hash.value("label"); + QString title = hash.value("label"); - if (!path.isEmpty()) + if (!title.isEmpty()) { - QString title = QFileInfo(path).completeBaseName(); - if (m_pendingThumbnailDownloadTypes.isEmpty()) { m_pendingThumbnailDownloadTypes.append(THUMBNAIL_BOXART); From 7731db9ed8228c7ba2654016b9520cc5c1e9fa46 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 26 Aug 2018 10:40:33 -0400 Subject: [PATCH 147/182] Qt: link to openssl so Qt will have it for later --- Makefile.common | 5 +++++ qb/config.libs.sh | 2 ++ ui/drivers/qt/ui_qt_window.cpp | 10 ++++++++++ 3 files changed, 17 insertions(+) diff --git a/Makefile.common b/Makefile.common index 09ab22222d..48b1b3b1bc 100644 --- a/Makefile.common +++ b/Makefile.common @@ -332,6 +332,11 @@ endif # Qt WIMP GUI +ifeq ($(HAVE_OPENSSL), 1) +DEFINES += $(OPENSSL_CFLAGS) +LIBS += $(OPENSSL_LIBS) +endif + ifeq ($(HAVE_QT), 1) OBJ += ui/drivers/ui_qt.o \ ui/drivers/qt/ui_qt_application.o \ diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 1a1da11dde..d0d94da004 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -281,6 +281,7 @@ if [ "$HAVE_QT" != 'no' ] && [ "$MOC_PATH" != 'none' ]; then check_pkgconf QT5CONCURRENT Qt5Concurrent 5.2 check_pkgconf QT5NETWORK Qt5Network 5.2 #check_pkgconf QT5WEBENGINE Qt5WebEngine 5.4 + check_pkgconf OPENSSL openssl 1.0.0 check_val '' QT5CORE -lQt5Core QT5CORE check_val '' QT5GUI -lQt5Gui QT5GUI @@ -288,6 +289,7 @@ if [ "$HAVE_QT" != 'no' ] && [ "$MOC_PATH" != 'none' ]; then check_val '' QT5CONCURRENT -lQt5Concurrent QT5CONCURRENT check_val '' QT5NETWORK -lQt5Network QT5NETWORK #check_val '' QT5WEBENGINE -lQt5WebEngine QT5WEBENGINE + check_val '' OPENSSL -lssl OPENSSL if [ "$HAVE_QT5CORE" = "no" ] || [ "$HAVE_QT5GUI" = "no" ] || [ "$HAVE_QT5WIDGETS" = "no" ] || [ "$HAVE_QT5CONCURRENT" = "no" ] || [ "$HAVE_QT5NETWORK" = "no" ]; then die : 'Notice: Not building Qt support, required libraries were not found.' diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 78ccdd45f7..d873443ee0 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -73,6 +73,8 @@ extern "C" { #include #include #include +#include +#include } #include "../../../AUTHORS.h" @@ -572,6 +574,14 @@ MainWindow::MainWindow(QWidget *parent) : #endif removeUpdateTempFiles(); + + { + const SSL_METHOD* method = TLSv1_method(); + + RARCH_LOG("[Qt]: Using %s\n", OPENSSL_VERSION_TEXT); + + RARCH_LOG("[Qt]: TLSv1 supports %d ciphers.\n", method->num_ciphers()); + } } MainWindow::~MainWindow() From 49e5fcd0cc074772993cb423e7b5938d6c753076 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 26 Aug 2018 10:44:55 -0400 Subject: [PATCH 148/182] Qt: only use openssl if we have it --- ui/drivers/qt/ui_qt_window.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index d873443ee0..22975dd405 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -73,8 +73,10 @@ extern "C" { #include #include #include +#ifdef HAVE_OPENSSL #include #include +#endif } #include "../../../AUTHORS.h" @@ -574,7 +576,7 @@ MainWindow::MainWindow(QWidget *parent) : #endif removeUpdateTempFiles(); - +#ifdef HAVE_OPENSSL { const SSL_METHOD* method = TLSv1_method(); @@ -582,6 +584,7 @@ MainWindow::MainWindow(QWidget *parent) : RARCH_LOG("[Qt]: TLSv1 supports %d ciphers.\n", method->num_ciphers()); } +#endif } MainWindow::~MainWindow() From 1d6a69d198bdbc5afafa1807b5e56a9d85bd63d8 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 26 Aug 2018 12:04:18 -0400 Subject: [PATCH 149/182] Qt: remove partially downloaded files on failure --- ui/drivers/qt/thumbnaildownload.cpp | 1 + ui/drivers/qt/updateretroarch.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ui/drivers/qt/thumbnaildownload.cpp b/ui/drivers/qt/thumbnaildownload.cpp index 4094cd495d..25351dbc37 100644 --- a/ui/drivers/qt/thumbnaildownload.cpp +++ b/ui/drivers/qt/thumbnaildownload.cpp @@ -124,6 +124,7 @@ void MainWindow::onThumbnailDownloadFinished() else { /*emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": HTTP Code " + QString::number(code));*/ + m_thumbnailDownloadFile.remove(); RARCH_ERR("[Qt]: Thumbnail download failed with HTTP status code: %d\n", code); diff --git a/ui/drivers/qt/updateretroarch.cpp b/ui/drivers/qt/updateretroarch.cpp index 454de2eb7c..1381345516 100644 --- a/ui/drivers/qt/updateretroarch.cpp +++ b/ui/drivers/qt/updateretroarch.cpp @@ -171,6 +171,8 @@ void MainWindow::onRetroArchUpdateDownloadFinished() QByteArray errorArray = reply->errorString().toUtf8(); const char *errorData = errorArray.constData(); + m_updateFile.remove(); + RARCH_ERR("[Qt]: RetroArch update ended prematurely: %s\n", errorData); emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": Code " + QString::number(code) + ": " + errorData); } From 12f1d003bbaccf2ef229ea6febba70131b9f4343 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 26 Aug 2018 16:04:01 -0400 Subject: [PATCH 150/182] Qt: openssl 1.1.0 broke their ABI --- ui/drivers/qt/ui_qt_window.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 22975dd405..bcacb88944 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -578,11 +578,17 @@ MainWindow::MainWindow(QWidget *parent) : removeUpdateTempFiles(); #ifdef HAVE_OPENSSL { - const SSL_METHOD* method = TLSv1_method(); +#if OPENSSL_VERSION_AT_LEAST(1,1) + const SSL_METHOD *method = TLS_method(); + SSL_CTX *ctx = SSL_CTX_new(method); + if (ctx) + SSL_CTX_free(ctx); +#else + const SSL_METHOD *method = TLSv1_method(); + RARCH_LOG("[Qt]: TLS supports %d ciphers.\n", method->num_ciphers()); +#endif RARCH_LOG("[Qt]: Using %s\n", OPENSSL_VERSION_TEXT); - - RARCH_LOG("[Qt]: TLSv1 supports %d ciphers.\n", method->num_ciphers()); } #endif } From 96380053322feba3cd3ec9fecc95f7ee87975033 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 26 Aug 2018 17:17:39 -0400 Subject: [PATCH 151/182] Qt: add UI option to set startup playlist, fixes #7103 --- intl/msg_hash_ja.h | 2 ++ intl/msg_hash_us.h | 2 ++ msg_hash.h | 1 + ui/drivers/qt/ui_qt_window.cpp | 29 ++++++++++++++++++++++++++++- ui/drivers/qt/viewoptionsdialog.cpp | 21 +++++++++++++++++++++ ui/drivers/qt/viewoptionsdialog.h | 1 + ui/drivers/ui_qt.h | 1 + 7 files changed, 56 insertions(+), 1 deletion(-) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index de56179467..ca2fca063d 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3792,3 +3792,5 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, "サムネイルをダウンロード") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, "他のダウンロードが実行中です。") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, + "起動時に表示するプレイリスト:") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 675a4809eb..b88c1049c4 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -7390,3 +7390,5 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, "Download thumbnail") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, "A download is already in progress.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, + "Start on playlist:") diff --git a/msg_hash.h b/msg_hash.h index e87319e4de..7e69b4e23c 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1913,6 +1913,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES, MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT, MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT, + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, MENU_ENUM_LABEL_VALUE_QT_MENU_TOOLS, MENU_ENUM_LABEL_VALUE_QT_MENU_HELP, MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER, diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index bcacb88944..a2251d1625 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -605,6 +605,33 @@ MainWindow::~MainWindow() removeGridItems(); } +QVector > MainWindow::getPlaylists() +{ + QVector > playlists; + int i; + + for (i = 0; i < m_listWidget->count(); i++) + { + QListWidgetItem *item = m_listWidget->item(i); + QPair pair; + QString label; + QString path; + + if (!item) + continue; + + label = item->text(); + path = item->data(Qt::UserRole).toString(); + + pair.first = label; + pair.second = path; + + playlists.append(pair); + } + + return playlists; +} + void MainWindow::onItemChanged() { ViewType viewType = getCurrentViewType(); @@ -633,7 +660,7 @@ QString MainWindow::getSpecialPlaylistPath(SpecialPlaylist playlist) switch (playlist) { case SPECIAL_PLAYLIST_HISTORY: - return m_historyPlaylistsItem->data(Qt::UserRole).toString(); + return (m_historyPlaylistsItem ? m_historyPlaylistsItem->data(Qt::UserRole).toString() : QString()); default: return QString(); } diff --git a/ui/drivers/qt/viewoptionsdialog.cpp b/ui/drivers/qt/viewoptionsdialog.cpp index a293b01a00..5d9bce0466 100644 --- a/ui/drivers/qt/viewoptionsdialog.cpp +++ b/ui/drivers/qt/viewoptionsdialog.cpp @@ -27,6 +27,7 @@ ViewOptionsDialog::ViewOptionsDialog(MainWindow *mainwindow, QWidget *parent) : ,m_saveLastTabCheckBox(new QCheckBox(this)) ,m_showHiddenFilesCheckBox(new QCheckBox(this)) ,m_themeComboBox(new QComboBox(this)) + ,m_startupPlaylistComboBox(new QComboBox(this)) ,m_highlightColorPushButton(new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CHOOSE), this)) ,m_highlightColor() ,m_highlightColorLabel(new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR), this)) @@ -65,6 +66,7 @@ ViewOptionsDialog::ViewOptionsDialog(MainWindow *mainwindow, QWidget *parent) : form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST), m_suggestLoadedCoreFirstCheckBox); form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT), m_allPlaylistsListMaxCountSpinBox); form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT), m_allPlaylistsGridMaxCountSpinBox); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST), m_startupPlaylistComboBox); form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME), m_themeComboBox); form->addRow(m_highlightColorLabel, m_highlightColorPushButton); @@ -133,7 +135,11 @@ void ViewOptionsDialog::loadViewOptions() { QColor highlightColor = m_settings->value("highlight_color", QApplication::palette().highlight().color()).value(); QPixmap highlightPixmap(m_highlightColorPushButton->iconSize()); + QVector > playlists = m_mainwindow->getPlaylists(); + QString initialPlaylist = m_settings->value("initial_playlist", m_mainwindow->getSpecialPlaylistPath(SPECIAL_PLAYLIST_HISTORY)).toString(); int themeIndex = 0; + int playlistIndex = 0; + int i; m_saveGeometryCheckBox->setChecked(m_settings->value("save_geometry", false).toBool()); m_saveDockPositionsCheckBox->setChecked(m_settings->value("save_dock_positions", false).toBool()); @@ -156,6 +162,20 @@ void ViewOptionsDialog::loadViewOptions() } showOrHideHighlightColor(); + + m_startupPlaylistComboBox->clear(); + + for (i = 0; i < playlists.count(); i++) + { + const QPair &pair = playlists.at(i); + + m_startupPlaylistComboBox->addItem(pair.first, pair.second); + } + + playlistIndex = m_startupPlaylistComboBox->findData(initialPlaylist, Qt::UserRole, Qt::MatchFixedString); + + if (playlistIndex >= 0) + m_startupPlaylistComboBox->setCurrentIndex(playlistIndex); } void ViewOptionsDialog::showOrHideHighlightColor() @@ -183,6 +203,7 @@ void ViewOptionsDialog::saveViewOptions() m_settings->setValue("suggest_loaded_core_first", m_suggestLoadedCoreFirstCheckBox->isChecked()); m_settings->setValue("all_playlists_list_max_count", m_allPlaylistsListMaxCountSpinBox->value()); m_settings->setValue("all_playlists_grid_max_count", m_allPlaylistsGridMaxCountSpinBox->value()); + m_settings->setValue("initial_playlist", m_startupPlaylistComboBox->currentData(Qt::UserRole).toString()); if (!m_mainwindow->customThemeString().isEmpty()) m_settings->setValue("custom_theme", m_customThemePath); diff --git a/ui/drivers/qt/viewoptionsdialog.h b/ui/drivers/qt/viewoptionsdialog.h index 7b5c7c71fe..faf0f143df 100644 --- a/ui/drivers/qt/viewoptionsdialog.h +++ b/ui/drivers/qt/viewoptionsdialog.h @@ -37,6 +37,7 @@ private: QCheckBox *m_saveLastTabCheckBox; QCheckBox *m_showHiddenFilesCheckBox; QComboBox *m_themeComboBox; + QComboBox *m_startupPlaylistComboBox; QPushButton *m_highlightColorPushButton; QColor m_highlightColor; QLabel *m_highlightColorLabel; diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 69d8b899eb..d55f076f6e 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -285,6 +285,7 @@ public: QHash getCurrentContentHash(); static double lerp(double x, double y, double a, double b, double d); QString getSpecialPlaylistPath(SpecialPlaylist playlist); + QVector > getPlaylists(); signals: void thumbnailChanged(const QPixmap &pixmap); From 32345e37f8cc9a673e61c52c1a928295934219cf Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 26 Aug 2018 18:14:08 -0400 Subject: [PATCH 152/182] Qt: OPENSSL_VERSION_AT_LEAST was reverted in openssl git because it is in fact broken --- ui/drivers/qt/ui_qt_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index a2251d1625..bf8ea5943e 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -578,7 +578,7 @@ MainWindow::MainWindow(QWidget *parent) : removeUpdateTempFiles(); #ifdef HAVE_OPENSSL { -#if OPENSSL_VERSION_AT_LEAST(1,1) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L const SSL_METHOD *method = TLS_method(); SSL_CTX *ctx = SSL_CTX_new(method); From 461dbf39ba156822e1b8c8b40b0447d6cdcc5fa7 Mon Sep 17 00:00:00 2001 From: Alfrix Date: Sun, 26 Aug 2018 20:00:36 -0300 Subject: [PATCH 153/182] Fix themes without menu icons --- menu/drivers/xmb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 9b75562be8..eec1544199 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2279,9 +2279,9 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, /* Menu icons are here waiting for theme support*/ { settings_t *settings = config_get_ptr(); - if (settings->uints.menu_xmb_theme != XMB_ICON_THEME_FLATUI || - settings->uints.menu_xmb_theme != XMB_ICON_THEME_NEOACTIVE || - settings->uints.menu_xmb_theme != XMB_ICON_THEME_RETROACTIVE || + if (settings->uints.menu_xmb_theme != XMB_ICON_THEME_FLATUI && + settings->uints.menu_xmb_theme != XMB_ICON_THEME_NEOACTIVE && + settings->uints.menu_xmb_theme != XMB_ICON_THEME_RETROACTIVE && settings->uints.menu_xmb_theme != XMB_ICON_THEME_PIXEL ) { switch (enum_idx) From 98fadf9b1f406a0b8e2ebfd6ff555249c87b158a Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 26 Aug 2018 23:24:22 -0400 Subject: [PATCH 154/182] Qt: remove partially downloaded thumbnail if transfer is canceled --- ui/drivers/qt/thumbnaildownload.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/drivers/qt/thumbnaildownload.cpp b/ui/drivers/qt/thumbnaildownload.cpp index 25351dbc37..ea4ea48839 100644 --- a/ui/drivers/qt/thumbnaildownload.cpp +++ b/ui/drivers/qt/thumbnaildownload.cpp @@ -168,6 +168,8 @@ void MainWindow::onThumbnailDownloadFinished() QByteArray errorArray = reply->errorString().toUtf8(); const char *errorData = errorArray.constData(); + m_thumbnailDownloadFile.remove(); + RARCH_ERR("[Qt]: Thumbnail download ended prematurely: %s\n", errorData); emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": Code " + QString::number(code) + ": " + errorData); } From 21f99b996570afc8c334627c03b497b7caa05b3c Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 26 Aug 2018 23:24:43 -0400 Subject: [PATCH 155/182] Qt: add right-click for playlists to download their thumbnail packs --- Makefile.common | 3 +- griffin/griffin_cpp.cpp | 1 + intl/msg_hash_ja.h | 4 + intl/msg_hash_us.h | 4 + msg_hash.h | 2 + ui/drivers/qt/playlist.cpp | 15 ++ ui/drivers/qt/thumbnailpackdownload.cpp | 314 ++++++++++++++++++++++++ ui/drivers/qt/ui_qt_window.cpp | 87 ++++++- ui/drivers/qt/updateretroarch.cpp | 80 +----- ui/drivers/ui_qt.h | 30 ++- 10 files changed, 454 insertions(+), 86 deletions(-) create mode 100644 ui/drivers/qt/thumbnailpackdownload.cpp diff --git a/Makefile.common b/Makefile.common index 48b1b3b1bc..90ce3fe265 100644 --- a/Makefile.common +++ b/Makefile.common @@ -352,7 +352,8 @@ OBJ += ui/drivers/ui_qt.o \ ui/drivers/qt/viewoptionsdialog.o \ ui/drivers/qt/playlist.o \ ui/drivers/qt/updateretroarch.o \ - ui/drivers/qt/thumbnaildownload.o + ui/drivers/qt/thumbnaildownload.o \ + ui/drivers/qt/thumbnailpackdownload.o MOC_HEADERS += ui/drivers/ui_qt.h \ ui/drivers/qt/ui_qt_load_core_window.h \ diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index 5c75dfefdb..47f25ab447 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -50,6 +50,7 @@ UI #include "../ui/drivers/qt/playlist.cpp" #include "../ui/drivers/qt/updateretroarch.cpp" #include "../ui/drivers/qt/thumbnaildownload.cpp" +#include "../ui/drivers/qt/thumbnailpackdownload.cpp" #endif /*============================================================ diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index ca2fca063d..d71ea6ff28 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3794,3 +3794,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, "他のダウンロードが実行中です。") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, "起動時に表示するプレイリスト:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, + "すべてのサムネイルをダウンロード") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, + "サムネイルのダウンロードが成功しました。") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index b88c1049c4..b0c9290fa0 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -7392,3 +7392,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, "A download is already in progress.") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, "Start on playlist:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, + "Download All Thumbnails") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, + "Thumbnails downloaded successfully.") diff --git a/msg_hash.h b/msg_hash.h index 7e69b4e23c..3e1cd59d77 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -2007,6 +2007,8 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp index 7113500f3d..af8bf6bc31 100644 --- a/ui/drivers/qt/playlist.cpp +++ b/ui/drivers/qt/playlist.cpp @@ -377,6 +377,7 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) QScopedPointer hideAction; QScopedPointer newPlaylistAction; QScopedPointer deletePlaylistAction; + QScopedPointer downloadAllThumbnailsAction; QPointer selectedAction; QPoint cursorPos = QCursor::pos(); QListWidgetItem *selectedItem = m_listWidget->itemAt(m_listWidget->viewport()->mapFromGlobal(cursorPos)); @@ -527,6 +528,13 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) menu->addMenu(associateMenu.data()); } + if (!specialPlaylist) + { + downloadAllThumbnailsAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS), this)); + + menu->addAction(downloadAllThumbnailsAction.data()); + } + selectedAction = menu->exec(cursorPos); if (!selectedAction) @@ -625,6 +633,13 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) } } } + else if (selectedItem && !specialPlaylist && selectedAction == downloadAllThumbnailsAction.data()) + { + int row = m_listWidget->row(selectedItem); + + if (row >= 0) + downloadAllThumbnails(currentPlaylistFileInfo.completeBaseName()); + } setCoreActions(); diff --git a/ui/drivers/qt/thumbnailpackdownload.cpp b/ui/drivers/qt/thumbnailpackdownload.cpp new file mode 100644 index 0000000000..75de1a6016 --- /dev/null +++ b/ui/drivers/qt/thumbnailpackdownload.cpp @@ -0,0 +1,314 @@ +#include +#include +#include + +#include "../ui_qt.h" + +extern "C" { +#include +#include +#include +#include "../../../tasks/tasks_internal.h" +#include "../../../verbosity.h" +#include "../../../config.def.h" +#include "../../../configuration.h" +#include "../../../version.h" +} + +#define USER_AGENT "RetroArch-WIMP/" PACKAGE_VERSION +#define PARTIAL_EXTENSION ".partial" +#define TEMP_EXTENSION ".tmp" +#define THUMBNAILPACK_URL_HEADER "http://thumbnailpacks.libretro.com/" +#define THUMBNAILPACK_EXTENSION ".zip" + +static void extractCB(void *task_data, void *user_data, const char *err) +{ + decompress_task_data_t *dec = (decompress_task_data_t*)task_data; + MainWindow *mainwindow = (MainWindow*)user_data; + + if (err) + RARCH_ERR("%s", err); + + if (dec) + { + if (filestream_exists(dec->source_file)) + filestream_delete(dec->source_file); + + free(dec->source_file); + free(dec); + } + + mainwindow->onThumbnailPackExtractFinished(string_is_empty(err)); +} + +void MainWindow::onThumbnailPackDownloadNetworkError(QNetworkReply::NetworkError code) +{ + QNetworkReply *reply = m_thumbnailPackDownloadReply.data(); + QByteArray errorStringArray; + const char *errorStringData = NULL; + + m_thumbnailPackDownloadProgressDialog->cancel(); + + if (!reply) + return; + + errorStringArray = reply->errorString().toUtf8(); + errorStringData = errorStringArray.constData(); + + RARCH_ERR("[Qt]: Network error code %d received: %s\n", code, errorStringData); + + /* Deleting the reply here seems to cause a strange heap-use-after-free crash. */ + /* + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + */ +} + +void MainWindow::onThumbnailPackDownloadNetworkSslErrors(const QList &errors) +{ + QNetworkReply *reply = m_thumbnailPackDownloadReply.data(); + int i; + + if (!reply) + return; + + for (i = 0; i < errors.count(); i++) + { + const QSslError &error = errors.at(i); + QString string = QString("Ignoring SSL error code ") + QString::number(error.error()) + ": " + error.errorString(); + QByteArray stringArray = string.toUtf8(); + const char *stringData = stringArray.constData(); + RARCH_ERR("[Qt]: %s\n", stringData); + } + + /* ignore all SSL errors for now, like self-signed, expired etc. */ + reply->ignoreSslErrors(); +} + +void MainWindow::onThumbnailPackDownloadCanceled() +{ + m_thumbnailPackDownloadProgressDialog->cancel(); +} + +void MainWindow::onThumbnailPackDownloadFinished() +{ + QString system; + QNetworkReply *reply = m_thumbnailPackDownloadReply.data(); + QNetworkReply::NetworkError error; + int code; + + m_thumbnailPackDownloadProgressDialog->cancel(); + + /* At least on Linux, the progress dialog will refuse to hide itself and will stay on screen in a corrupted way if we happen to show an error message in this function. processEvents() will sometimes fix it, other times not... seems random. */ + qApp->processEvents(); + + if (!reply) + return; + + system = reply->property("system").toString(); + + error = reply->error(); + code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (m_thumbnailPackDownloadFile.isOpen()) + m_thumbnailPackDownloadFile.close(); + + if (code != 200) + { + QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + + if (!redirectUrl.isEmpty()) + { + QByteArray redirectUrlArray = redirectUrl.toString().toUtf8(); + const char *redirectUrlData = redirectUrlArray.constData(); + + RARCH_LOG("[Qt]: Thumbnail pack download got redirect with HTTP code %d: %s\n", code, redirectUrlData); + + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + + downloadAllThumbnails(system, redirectUrl); + + return; + } + else + { + emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": HTTP Code " + QString::number(code)); + + m_thumbnailPackDownloadFile.remove(); + + RARCH_ERR("[Qt]: Thumbnail pack download failed with HTTP status code: %d\n", code); + + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + + return; + } + } + + if (error == QNetworkReply::NoError) + { + int index = m_thumbnailPackDownloadFile.fileName().lastIndexOf(PARTIAL_EXTENSION); + QString newFileName = m_thumbnailPackDownloadFile.fileName().left(index); + QFile newFile(newFileName); + + /* rename() requires the old file to be deleted first if it exists */ + if (newFile.exists() && !newFile.remove()) + RARCH_ERR("[Qt]: Thumbnail pack download finished, but old file could not be deleted.\n"); + else + { + if (m_thumbnailPackDownloadFile.rename(newFileName)) + { + settings_t *settings = config_get_ptr(); + + if (settings) + { + RARCH_LOG("[Qt]: Thumbnail pack download finished successfully.\n"); + emit extractArchiveDeferred(newFileName, settings->paths.directory_thumbnails, TEMP_EXTENSION, extractCB); + } + } + else + { + RARCH_ERR("[Qt]: Thumbnail pack download finished, but temp file could not be renamed.\n"); + emit showErrorMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE)); + } + } + } + else + { + QByteArray errorArray = reply->errorString().toUtf8(); + const char *errorData = errorArray.constData(); + + m_thumbnailPackDownloadFile.remove(); + + RARCH_ERR("[Qt]: Thumbnail pack download ended prematurely: %s\n", errorData); + emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": Code " + QString::number(code) + ": " + errorData); + } + + reply->disconnect(); + reply->close(); + reply->deleteLater(); +} + +void MainWindow::onThumbnailPackDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + QNetworkReply *reply = m_thumbnailPackDownloadReply.data(); + int progress = (bytesReceived / (float)bytesTotal) * 100.0f; + + if (!reply) + return; + + m_thumbnailPackDownloadProgressDialog->setValue(progress); +} + +void MainWindow::onThumbnailPackDownloadReadyRead() +{ + QNetworkReply *reply = m_thumbnailPackDownloadReply.data(); + + if (!reply) + return; + + m_thumbnailPackDownloadFile.write(reply->readAll()); +} + +void MainWindow::downloadAllThumbnails(QString system, QUrl url) +{ + QString urlString; + QNetworkReply *reply = NULL; + QNetworkRequest request; + QByteArray urlArray; + settings_t *settings = config_get_ptr(); + const char *urlData = NULL; + + if (!settings) + return; + + urlString = QString(THUMBNAILPACK_URL_HEADER) + system + THUMBNAILPACK_EXTENSION; + + if (url.isEmpty()) + url = urlString; + + request.setUrl(url); + + urlArray = url.toString().toUtf8(); + urlData = urlArray.constData(); + + if (m_thumbnailPackDownloadFile.isOpen()) + { + RARCH_ERR("[Qt]: File is already open.\n"); + return; + } + else + { + QString dirString = QString(settings->paths.directory_thumbnails); + QString fileName = dirString + "/" + system + THUMBNAILPACK_EXTENSION + PARTIAL_EXTENSION; + QDir dir; + QByteArray fileNameArray = fileName.toUtf8(); + const char *fileNameData = fileNameArray.constData(); + + dir.mkpath(dirString); + + m_thumbnailPackDownloadFile.setFileName(fileName); + + if (!m_thumbnailPackDownloadFile.open(QIODevice::WriteOnly)) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Could not open file for writing: %s\n", fileNameData); + return; + } + } + + RARCH_LOG("[Qt]: Starting thumbnail pack download...\n"); + RARCH_LOG("[Qt]: Downloading URL %s\n", urlData); + + request.setHeader(QNetworkRequest::UserAgentHeader, USER_AGENT); + + m_thumbnailPackDownloadProgressDialog->setWindowModality(Qt::NonModal); + m_thumbnailPackDownloadProgressDialog->setMinimumDuration(0); + m_thumbnailPackDownloadProgressDialog->setRange(0, 100); + m_thumbnailPackDownloadProgressDialog->setAutoClose(true); + m_thumbnailPackDownloadProgressDialog->setAutoReset(true); + m_thumbnailPackDownloadProgressDialog->setValue(0); + m_thumbnailPackDownloadProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_DOWNLOADING)) + "..."); + m_thumbnailPackDownloadProgressDialog->setCancelButtonText(tr("Cancel")); + m_thumbnailPackDownloadProgressDialog->show(); + + m_thumbnailPackDownloadReply = m_networkManager->get(request); + + reply = m_thumbnailPackDownloadReply.data(); + reply->setProperty("system", system); + + /* make sure any previous connection is removed first */ + disconnect(m_thumbnailPackDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); + disconnect(m_thumbnailPackDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailPackDownloadProgressDialog, SLOT(cancel())); + connect(m_thumbnailPackDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); + connect(m_thumbnailPackDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailPackDownloadProgressDialog, SLOT(cancel())); + + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onThumbnailPackDownloadNetworkError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(sslErrors(const QList&)), this, SLOT(onThumbnailPackDownloadNetworkSslErrors(const QList&))); + connect(reply, SIGNAL(finished()), this, SLOT(onThumbnailPackDownloadFinished())); + connect(reply, SIGNAL(readyRead()), this, SLOT(onThumbnailPackDownloadReadyRead())); + connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onThumbnailPackDownloadProgress(qint64, qint64))); +} + +void MainWindow::onThumbnailPackExtractFinished(bool success) +{ + m_updateProgressDialog->cancel(); + + if (!success) + { + RARCH_ERR("[Qt]: Thumbnail pack extraction failed.\n"); + emit showErrorMessageDeferred(msg_hash_to_str(MSG_DECOMPRESSION_FAILED)); + return; + } + + RARCH_LOG("[Qt]: Thumbnail pack extracted successfully.\n"); + + emit showInfoMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY)); + + /* reload thumbnail image */ + emit itemChanged(); +} diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index bf8ea5943e..c84ae8f878 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -321,8 +321,12 @@ MainWindow::MainWindow(QWidget *parent) : ,m_updateFile() ,m_updateReply() ,m_thumbnailDownloadProgressDialog(new QProgressDialog()) + ,m_thumbnailDownloadFile() ,m_thumbnailDownloadReply() ,m_pendingThumbnailDownloadTypes() + ,m_thumbnailPackDownloadProgressDialog(new QProgressDialog()) + ,m_thumbnailPackDownloadFile() + ,m_thumbnailPackDownloadReply() { settings_t *settings = config_get_ptr(); QDir playlistDir(settings->paths.directory_playlist); @@ -341,9 +345,12 @@ MainWindow::MainWindow(QWidget *parent) : int i = 0; qRegisterMetaType >("ThumbnailWidget"); + qRegisterMetaType("retro_task_callback_t"); + /* Cancel all progress dialogs immediately since they show as soon as they're constructed. */ m_updateProgressDialog->cancel(); m_thumbnailDownloadProgressDialog->cancel(); + m_thumbnailPackDownloadProgressDialog->cancel(); m_gridProgressWidget = new QWidget(); gridProgressLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PROGRESS), m_gridProgressWidget); @@ -553,7 +560,7 @@ MainWindow::MainWindow(QWidget *parent) : /* these are always queued */ connect(this, SIGNAL(showErrorMessageDeferred(QString)), this, SLOT(onShowErrorMessage(QString)), Qt::QueuedConnection); connect(this, SIGNAL(showInfoMessageDeferred(QString)), this, SLOT(onShowInfoMessage(QString)), Qt::QueuedConnection); - connect(this, SIGNAL(extractArchiveDeferred(QString)), this, SLOT(onExtractArchive(QString)), Qt::QueuedConnection); + connect(this, SIGNAL(extractArchiveDeferred(QString,QString,QString,retro_task_callback_t)), this, SLOT(onExtractArchive(QString,QString,QString,retro_task_callback_t)), Qt::QueuedConnection); m_timer->start(TIMER_MSEC); @@ -3032,6 +3039,84 @@ void MainWindow::onShowInfoMessage(QString msg) showMessageBox(msg, MainWindow::MSGBOX_TYPE_INFO, Qt::ApplicationModal, false); } +int MainWindow::onExtractArchive(QString path, QString extractionDir, QString tempExtension, retro_task_callback_t cb) +{ + QByteArray pathArray = path.toUtf8(); + QByteArray dirArray = extractionDir.toUtf8(); + const char *file = pathArray.constData(); + const char *dir = dirArray.constData(); + file_archive_transfer_t state; + struct archive_extract_userdata userdata; + struct string_list *file_list = file_archive_get_file_list(file, NULL); + bool returnerr = true; + unsigned i; + + if (!file_list || file_list->size == 0) + { + showMessageBox("Error: Archive is empty.", MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Downloaded archive is empty?\n"); + return -1; + } + + for (i = 0; i < file_list->size; i++) + { + QFile fileObj(file_list->elems[i].data); + + if (fileObj.exists()) + { + if (!fileObj.remove()) + { + /* if we cannot delete the existing file to update it, rename it for now and delete later */ + QFile fileTemp(fileObj.fileName() + tempExtension); + + if (fileTemp.exists()) + { + if (!fileTemp.remove()) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Could not delete file: %s\n", file_list->elems[i].data); + return -1; + } + } + + if (!fileObj.rename(fileTemp.fileName())) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Could not rename file: %s\n", file_list->elems[i].data); + return -1; + } + } + } + } + + string_list_free(file_list); + + memset(&state, 0, sizeof(state)); + memset(&userdata, 0, sizeof(userdata)); + + state.type = ARCHIVE_TRANSFER_INIT; + + m_updateProgressDialog->setWindowModality(Qt::NonModal); + m_updateProgressDialog->setMinimumDuration(0); + m_updateProgressDialog->setRange(0, 0); + m_updateProgressDialog->setAutoClose(true); + m_updateProgressDialog->setAutoReset(true); + m_updateProgressDialog->setValue(0); + m_updateProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_EXTRACTING)) + "..."); + m_updateProgressDialog->setCancelButtonText(QString()); + m_updateProgressDialog->show(); + + if (!task_push_decompress(file, dir, + NULL, NULL, NULL, + cb, this)) + { + m_updateProgressDialog->cancel(); + return -1; + } + + return returnerr; +} + static void* ui_window_qt_init(void) { ui_window.qtWindow = new MainWindow(); diff --git a/ui/drivers/qt/updateretroarch.cpp b/ui/drivers/qt/updateretroarch.cpp index 1381345516..9f524abc9e 100644 --- a/ui/drivers/qt/updateretroarch.cpp +++ b/ui/drivers/qt/updateretroarch.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -157,7 +157,7 @@ void MainWindow::onRetroArchUpdateDownloadFinished() if (m_updateFile.rename(newFileName)) { RARCH_LOG("[Qt]: RetroArch update finished downloading successfully.\n"); - emit extractArchiveDeferred(newFileName); + emit extractArchiveDeferred(newFileName, ".", TEMP_EXTENSION, extractCB); } else { @@ -198,82 +198,6 @@ void MainWindow::onUpdateRetroArchFinished(bool success) emit showInfoMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED)); } -int MainWindow::onExtractArchive(QString path) -{ - QByteArray pathArray = path.toUtf8(); - const char *file = pathArray.constData(); - file_archive_transfer_t state; - struct archive_extract_userdata userdata; - struct string_list *file_list = file_archive_get_file_list(file, NULL); - bool returnerr = true; - unsigned i; - - if (!file_list || file_list->size == 0) - { - showMessageBox("Error: Archive is empty.", MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - RARCH_ERR("[Qt]: Downloaded archive is empty?\n"); - return -1; - } - - for (i = 0; i < file_list->size; i++) - { - QFile fileObj(file_list->elems[i].data); - - if (fileObj.exists()) - { - if (!fileObj.remove()) - { - /* if we cannot delete the existing file to update it, rename it for now and delete later */ - QFile fileTemp(fileObj.fileName() + TEMP_EXTENSION); - - if (fileTemp.exists()) - { - if (!fileTemp.remove()) - { - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - RARCH_ERR("[Qt]: Could not delete file: %s\n", file_list->elems[i].data); - return -1; - } - } - - if (!fileObj.rename(fileTemp.fileName())) - { - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); - RARCH_ERR("[Qt]: Could not rename file: %s\n", file_list->elems[i].data); - return -1; - } - } - } - } - - string_list_free(file_list); - - memset(&state, 0, sizeof(state)); - memset(&userdata, 0, sizeof(userdata)); - - state.type = ARCHIVE_TRANSFER_INIT; - - m_updateProgressDialog->setWindowModality(Qt::NonModal); - m_updateProgressDialog->setMinimumDuration(0); - m_updateProgressDialog->setRange(0, 0); - m_updateProgressDialog->setAutoClose(true); - m_updateProgressDialog->setAutoReset(true); - m_updateProgressDialog->setValue(0); - m_updateProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_EXTRACTING)) + "..."); - m_updateProgressDialog->setCancelButtonText(QString()); - m_updateProgressDialog->show(); - - if (!task_push_decompress(file, ".", - NULL, NULL, NULL, - extractCB, this)) - { - m_updateProgressDialog->cancel(); - return -1; - } - - return returnerr; -} - void MainWindow::onUpdateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { QNetworkReply *reply = m_updateReply.data(); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index d55f076f6e..656d5bd967 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -41,6 +41,7 @@ extern "C" { #include #include +#include #include "../ui_companion_driver.h" #include "../../gfx/video_driver.h" } @@ -297,7 +298,7 @@ signals: void gotReloadShaderParams(); void showErrorMessageDeferred(QString msg); void showInfoMessageDeferred(QString msg); - void extractArchiveDeferred(QString path); + void extractArchiveDeferred(QString path, QString extractionDir, QString tempExtension, retro_task_callback_t cb); void itemChanged(); void gotThumbnailDownload(QString system, QString title); @@ -337,8 +338,10 @@ public slots: void showDocs(); void updateRetroArchNightly(); void onUpdateRetroArchFinished(bool success); + void onThumbnailPackExtractFinished(bool success); void deferReloadShaderParams(); void downloadThumbnail(QString system, QString title, QUrl url = QUrl()); + void downloadAllThumbnails(QString system, QUrl url = QUrl()); private slots: void onLoadCoreClicked(const QStringList &extensionFilters = QStringList()); @@ -371,24 +374,33 @@ private slots: void onGridItemClicked(ThumbnailWidget *thumbnailWidget = NULL); void onPlaylistFilesDropped(QStringList files); void onShaderParamsClicked(); + void onShowErrorMessage(QString msg); + void onShowInfoMessage(QString msg); + void onContributorsClicked(); + void onItemChanged(); + int onExtractArchive(QString path, QString extractionDir, QString tempExtension, retro_task_callback_t cb); + void onUpdateNetworkError(QNetworkReply::NetworkError code); void onUpdateNetworkSslErrors(const QList &errors); void onRetroArchUpdateDownloadFinished(); void onUpdateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); void onUpdateDownloadReadyRead(); void onUpdateDownloadCanceled(); - void onShowErrorMessage(QString msg); - void onShowInfoMessage(QString msg); - void onContributorsClicked(); + void onThumbnailDownloadNetworkError(QNetworkReply::NetworkError code); void onThumbnailDownloadNetworkSslErrors(const QList &errors); void onThumbnailDownloadFinished(); void onThumbnailDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); void onThumbnailDownloadReadyRead(); void onThumbnailDownloadCanceled(); - void onItemChanged(); void onDownloadThumbnail(QString system, QString title); - int onExtractArchive(QString path); + + void onThumbnailPackDownloadNetworkError(QNetworkReply::NetworkError code); + void onThumbnailPackDownloadNetworkSslErrors(const QList &errors); + void onThumbnailPackDownloadFinished(); + void onThumbnailPackDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void onThumbnailPackDownloadReadyRead(); + void onThumbnailPackDownloadCanceled(); private: void setCurrentCoreLabel(); @@ -463,14 +475,20 @@ private: QElapsedTimer m_statusMessageElapsedTimer; QPointer m_shaderParamsDialog; QNetworkAccessManager *m_networkManager; + QProgressDialog *m_updateProgressDialog; QFile m_updateFile; QPointer m_updateReply; + QProgressDialog *m_thumbnailDownloadProgressDialog; QFile m_thumbnailDownloadFile; QPointer m_thumbnailDownloadReply; QStringList m_pendingThumbnailDownloadTypes; + QProgressDialog *m_thumbnailPackDownloadProgressDialog; + QFile m_thumbnailPackDownloadFile; + QPointer m_thumbnailPackDownloadReply; + protected: void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *event); From aa0889ec297db4808eeeb6aca5420daf315c4b7a Mon Sep 17 00:00:00 2001 From: Alfrix Date: Mon, 27 Aug 2018 10:43:31 -0300 Subject: [PATCH 156/182] Fallback to default icon in custom playlists --- menu/drivers/xmb.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index eec1544199..380bc8f9e4 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2028,6 +2028,13 @@ static void xmb_context_reset_horizontal_list( file_path_str(FILE_PATH_PNG_EXTENSION), PATH_MAX_LENGTH * sizeof(char)); + /* If the playlist icon doesn't exist return default */ + + if (!filestream_exists(texturepath)) + fill_pathname_join_concat(texturepath, iconpath, "default", + file_path_str(FILE_PATH_PNG_EXTENSION), + PATH_MAX_LENGTH * sizeof(char)); + ti.width = 0; ti.height = 0; ti.pixels = NULL; @@ -2045,10 +2052,21 @@ static void xmb_context_reset_horizontal_list( image_texture_free(&ti); } - strlcat(iconpath, sysname, PATH_MAX_LENGTH * sizeof(char)); - fill_pathname_join_delim(content_texturepath, iconpath, + fill_pathname_join_delim(sysname, sysname, file_path_str(FILE_PATH_CONTENT_BASENAME), '-', PATH_MAX_LENGTH * sizeof(char)); + strlcat(content_texturepath, iconpath, PATH_MAX_LENGTH * sizeof(char)); + strlcat(content_texturepath, sysname, PATH_MAX_LENGTH * sizeof(char)); + + /* If the content icon doesn't exist return default-content */ + + if (!filestream_exists(content_texturepath)) + { + strlcat(iconpath, "default", PATH_MAX_LENGTH * sizeof(char)); + fill_pathname_join_delim(content_texturepath, iconpath, + file_path_str(FILE_PATH_CONTENT_BASENAME), '-', + PATH_MAX_LENGTH * sizeof(char)); + } if (image_texture_load(&ti, content_texturepath)) { From 6d1e04dd9c0ec6b58ac96949c679b41b43b7ac93 Mon Sep 17 00:00:00 2001 From: Alfrix Date: Mon, 27 Aug 2018 10:45:07 -0300 Subject: [PATCH 157/182] Cleanup --- menu/drivers/xmb.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 380bc8f9e4..049da29623 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -5295,13 +5295,10 @@ static int xmb_list_push(void *data, void *userdata, } #endif #if defined(HAVE_NETWORKING) + if (settings->bools.menu_show_online_updater && !settings->bools.kiosk_mode_enable) { - settings_t *settings = config_get_ptr(); - if (settings->bools.menu_show_online_updater && !settings->bools.kiosk_mode_enable) - { - entry.enum_idx = MENU_ENUM_LABEL_ONLINE_UPDATER; - menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); - } + entry.enum_idx = MENU_ENUM_LABEL_ONLINE_UPDATER; + menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); } #endif if (!settings->bools.menu_content_show_settings && !string_is_empty(settings->paths.menu_content_show_settings_password)) From 8a5d092e5b894af43800e412cb93626ca90bea16 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Mon, 27 Aug 2018 16:09:12 +0200 Subject: [PATCH 158/182] (dispserv_x11.c) Make variable bigger to avoid all the warnings and use snprintf --- gfx/display_servers/dispserv_x11.c | 35 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/gfx/display_servers/dispserv_x11.c b/gfx/display_servers/dispserv_x11.c index aeb45e71f0..dbc22ece98 100644 --- a/gfx/display_servers/dispserv_x11.c +++ b/gfx/display_servers/dispserv_x11.c @@ -14,6 +14,8 @@ * You should have received a copy of the GNU General Public License along with RetroArch. * If not, see . */ +#include +#include #include "../video_display_server.h" #include "../common/x11_common.h" @@ -21,9 +23,6 @@ #include "../video_driver.h" /* needed to set refresh rate in set resolution */ #include "../video_crt_switch.h" /* needed to set aspect for low res in linux */ -#include -#include - static char old_mode[150]; static char new_mode[150]; static bool crt_en = false; @@ -99,7 +98,7 @@ static bool x11_set_resolution(void *data, float pixel_clock = 0; char xrandr[250]; char fbset[150]; - char output[150]; + char output[250]; crt_en = true; @@ -205,58 +204,58 @@ static bool x11_set_resolution(void *data, /* create progressive newmode from modline variables */ if (height < 300) { - sprintf(xrandr,"xrandr --newmode \"%dx%d_%0.2f\" %lf %d %d %d %d %d %d %d %d -hsync -vsync", width, height, hz, pixel_clock, width, hfp, hsp, hbp, height, vfp, vsp, vbp); + snprintf(xrandr, sizeof(xrandr), "xrandr --newmode \"%dx%d_%0.2f\" %lf %d %d %d %d %d %d %d %d -hsync -vsync", width, height, hz, pixel_clock, width, hfp, hsp, hbp, height, vfp, vsp, vbp); system(xrandr); } /* create interlaced newmode from modline variables */ if (height > 300) { - sprintf(xrandr,"xrandr --newmode \"%dx%d_%0.2f\" %lf %d %d %d %d %d %d %d %d interlace -hsync -vsync", width, height, hz, pixel_clock, width, hfp, hsp, hbp, height, vfp, vsp, vbp); + snprintf(xrandr, sizeof(xrandr), "xrandr --newmode \"%dx%d_%0.2f\" %lf %d %d %d %d %d %d %d %d interlace -hsync -vsync", width, height, hz, pixel_clock, width, hfp, hsp, hbp, height, vfp, vsp, vbp); system(xrandr); } /* variable for new mode */ - sprintf(new_mode,"%dx%d_%0.2f", width, height, hz); + snprintf(new_mode, sizeof(new_mode), "%dx%d_%0.2f", width, height, hz); /* need to run loops for DVI0 - DVI-2 and VGA0 - VGA-2 outputs to add and delete modes */ for (i =0; i < 3; i++) { - sprintf(output,"xrandr --addmode %s%d %s", "DVI",i ,new_mode); + snprintf(output, sizeof(output), "xrandr --addmode %s%d %s", "DVI",i ,new_mode); system(output); - sprintf(output,"xrandr --delmode %s%d %s", "DVI",i ,old_mode); + snprintf(output, sizeof(output), "xrandr --delmode %s%d %s", "DVI",i ,old_mode); system(output); } for (i =0; i < 3; i++) { - sprintf(output,"xrandr --addmode %s-%d %s", "DVI",i ,new_mode); + snprintf(output, sizeof(output), "xrandr --addmode %s-%d %s", "DVI",i ,new_mode); system(output); - sprintf(output,"xrandr --delmode %s-%d %s", "DVI",i ,old_mode); + snprintf(output, sizeof(output), "xrandr --delmode %s-%d %s", "DVI",i ,old_mode); system(output); } for (i =0; i < 3; i++) { - sprintf(output,"xrandr --addmode %s%d %s", "VGA",i ,new_mode); + snprintf(output, sizeof(output), "xrandr --addmode %s%d %s", "VGA",i ,new_mode); system(output); - sprintf(output,"xrandr --delmode %s%d %s", "VGA",i ,old_mode); + snprintf(output, sizeof(output), "xrandr --delmode %s%d %s", "VGA",i ,old_mode); system(output); } for (i =0; i < 3; i++) { - sprintf(output,"xrandr --addmode %s-%d %s", "VGA",i ,new_mode); + snprintf(output, sizeof(output), "xrandr --addmode %s-%d %s", "VGA",i ,new_mode); system(output); - sprintf(output,"xrandr --delmode %s-%d %s", "VGA",i ,old_mode); + snprintf(output, sizeof(output), "xrandr --delmode %s-%d %s", "VGA",i ,old_mode); system(output); } - sprintf(output,"xrandr -s %s", new_mode); + snprintf(output, sizeof(output), "xrandr -s %s", new_mode); system(output); /* remove old mode */ - sprintf(output,"xrandr --rmmode %s", old_mode); + snprintf(output, sizeof(output), "xrandr --rmmode %s", old_mode); system(output); system("xdotool windowactivate $(xdotool search --class RetroArch)"); /* needs xdotool installed. needed to recaputure window. */ /* variable for old mode */ - sprintf(old_mode,"%s", new_mode); + snprintf(old_mode, sizeof(old_mode), "%s", new_mode); system("xdotool windowactivate $(xdotool search --class RetroArch)"); /* needs xdotool installed. needed to recaputure window. */ /* Second run needed as some times it runs to fast to capture first time */ From 23836bfba96a7aab3745e434e4c24ce1decea1c2 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 27 Aug 2018 13:38:37 -0400 Subject: [PATCH 159/182] use_thread option for screenshot was backwards --- tasks/task_screenshot.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasks/task_screenshot.c b/tasks/task_screenshot.c index 80c3b90cee..2ea95618ac 100644 --- a/tasks/task_screenshot.c +++ b/tasks/task_screenshot.c @@ -260,14 +260,14 @@ static bool screenshot_dump( task->handler = task_screenshot_handler; if (use_thread) - return screenshot_dump_direct(state); - else { if (!savestate) - task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); + task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); task_queue_push(task); } + else + return screenshot_dump_direct(state); return true; } From 0116f675b90b4c56afb048c8e65831a1b56a6751 Mon Sep 17 00:00:00 2001 From: altiereslima Date: Mon, 27 Aug 2018 17:21:56 -0300 Subject: [PATCH 160/182] Update brazilian portuguese translation --- intl/msg_hash_pt_br.h | 432 ++++++++++++++++++++++-------------------- 1 file changed, 225 insertions(+), 207 deletions(-) diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index e939534814..7b8204db0a 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -12,7 +12,7 @@ MSG_HASH( ) MSG_HASH( MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, - "Comando Netplay desconhecido recebido" + "Recebido um comando de jogo em rede desconhecido" ) MSG_HASH( MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, @@ -52,7 +52,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_YOU_HAVE_JOINED_WITH_INPUT_DEVICES_S, - "Você se juntou aos dispositivos de entrada %.*s" + "Você se juntou ao dispositivo de entrada %.*s" ) MSG_HASH( MSG_NETPLAY_PLAYER_S_LEFT, @@ -64,39 +64,39 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_S_HAS_JOINED_WITH_INPUT_DEVICES_S, - "%.*s juntou-se a dispositivos de entrada %.*s" + "%.*s juntou-se aos dispositivos de entrada %.*s" ) MSG_HASH( MSG_NETPLAY_NOT_RETROARCH, - "Uma tentativa de conexão com o netplay falhou porque o par não está executando o RetroArch ou está executando uma versão antiga do RetroArch." + "Uma tentativa de conexão de jogo em rede falhou porque o par não está executando o RetroArch ou está executando uma versão antiga do RetroArch." ) MSG_HASH( MSG_NETPLAY_OUT_OF_DATE, - "O par netplay está executando uma versão antiga do RetroArch. Não pode conectar." + "O par de jogo em rede está executando uma versão antiga do RetroArch. Não é possível conectar." ) MSG_HASH( MSG_NETPLAY_DIFFERENT_VERSIONS, - "ATENÇÃO: Um par de Netplay está executando uma versão diferente do RetroArch. Se ocorrerem problemas, use a mesma versão." + "ATENÇÃO: Um par de jogo em rede está executando uma versão diferente do RetroArch. Se ocorrerem problemas, use a mesma versão." ) MSG_HASH( MSG_NETPLAY_DIFFERENT_CORES, - "Um par de netplay está executando um núcleo diferente. Não pode conectar." + "Um par de jogo em rede está executando um núcleo diferente. Não é possível conectar." ) MSG_HASH( MSG_NETPLAY_DIFFERENT_CORE_VERSIONS, - "ATENÇÃO: Um par de Netplay está executando uma versão diferente do núcleo. Se ocorrerem problemas, use a mesma versão." + "ATENÇÃO: Um par de jogo em rede está executando uma versão diferente do núcleo. Se ocorrerem problemas, use a mesma versão." ) MSG_HASH( MSG_NETPLAY_ENDIAN_DEPENDENT, - "Este núcleo não suporta Netplay inter-arquitetura entre estes sistemas" + "Este núcleo não suporta jogo em rede entre diferentes arquiteturas de sistemas" ) MSG_HASH( MSG_NETPLAY_PLATFORM_DEPENDENT, - "Este núcleo não suporta Netplay inter-arquitetura" + "Este núcleo não suporta jogo em rede entre diferentes sistemas" ) MSG_HASH( MSG_NETPLAY_ENTER_PASSWORD, - "Digite a senha do servidor de Netplay:" + "Digite a senha do servidor de jogo em rede:" ) MSG_HASH( MSG_NETPLAY_INCORRECT_PASSWORD, @@ -108,11 +108,11 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_SERVER_HANGUP, - "Um cliente do Netplay desconectou" + "Um cliente de jogo em rede desconectou" ) MSG_HASH( MSG_NETPLAY_CLIENT_HANGUP, - "Desconectado do Netplay" + "Desconectado do jogo em rede" ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, @@ -132,7 +132,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_PEER_PAUSED, - "Par do Netplay \"%s\" pausou" + "Par do jogo em rede \"%s\" pausou" ) MSG_HASH( MSG_NETPLAY_CHANGED_NICK, @@ -172,7 +172,7 @@ MSG_HASH( ) MSG_HASH( MSG_CONNECTING_TO_NETPLAY_HOST, - "Conectando ao hospedeiro de Netplay" + "Conectando ao hospedeiro de jogo em rede" ) MSG_HASH( MSG_CONNECTING_TO_PORT, @@ -184,7 +184,7 @@ MSG_HASH( ) MSG_HASH( MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, - "Desculpe, não implementado: núcleos que não exigem conteúdo não podem participar do Netplay." + "Desculpe, não implementado: núcleos que não exigem conteúdo não podem participar do jogo em rede." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, @@ -240,7 +240,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, - "Salas de Netplay" + "Salas de Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, @@ -288,7 +288,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, - "Áudio Mudo" + "Silenciar Áudio" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, @@ -818,6 +818,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, "Controlar Velocidade Máxima de Execução" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VRR_RUNLOOP_ENABLE, + "Sincronizar Taxa de Atualização Exata ao Conteúdo (G-Sync, FreeSync)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, "Controle de Quadros" @@ -868,7 +872,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, - "O Que É Um Núcleo?" + "O Que é um Núcleo?" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, @@ -1248,7 +1252,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, - "Alternar modo jogador/espectador do Netplay" + "Alternar modo jogador/espectador do jogo em rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, @@ -1648,7 +1652,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY, - "Netplay" + "Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_SLAVES, @@ -1656,7 +1660,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, - "Verificar Quadros do Netplay" + "Verificar Quadros do Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, @@ -1668,27 +1672,27 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, - "Atraso de Quadros do Netplay" + "Atraso de Quadros do Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, - "Desconectar do hospedeiro de Netplay" + "Desconectar do hospedeiro de jogo em rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, - "Habilitar Netplay" + "Habilitar Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, - "Conectar ao hospedeiro de Netplay" + "Conectar ao hospedeiro de jogo em rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, - "Iniciar hospedeiro de Netplay" + "Iniciar hospedeiro de jogo em rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, - "Parar hospedeiro de Netplay" + "Parar hospedeiro de jogo em rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, @@ -1700,7 +1704,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, - "Habilitar Cliente Netplay" + "Habilitar Cliente de Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, @@ -1712,7 +1716,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, - "Anunciar Netplay Publicamente" + "Anunciar Jogo em Rede Publicamente" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_REQUEST_DEVICE_I, @@ -1724,7 +1728,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, - "Configurações do Netplay" + "Configurações do jogo em rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG, @@ -1764,11 +1768,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_START_AS_SPECTATOR, - "Modo Espectador do Netplay" + "Modo Espectador do Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, - "Modo sem Estados de Jogo do Netplay" + "Modo sem Estados de Jogo do Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, @@ -1776,15 +1780,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, - "Habilitar Espectador do Netplay" + "Habilitar Espectador do Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, - "Porta TCP do Netplay" + "Porta TCP do Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, - "Travessia de NAT do Netplay" + "Travessia de NAT do Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, @@ -1860,7 +1864,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, - "Nenhum hospedeiro de Netplay encontrado." + "Nenhum hospedeiro de jogo em rede encontrado." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, @@ -1920,7 +1924,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_ONSCREEN_NOTIFICATIONS_SETTINGS, - "Ajustar Notificações na Tela" + "Ajusta as Notificações na Tela" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, @@ -2180,7 +2184,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CONTENT_DIR, - "Salvar Arquivo de Remapeamento de Jogo do Diretório de Conteúdo" + "Salvar Remapeamento de Controle para o Diretório de Conteúdo" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, @@ -2212,11 +2216,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME, - "Retomar" + "Continuar" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, - "Retomar" + "Continuar" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, @@ -2660,7 +2664,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, - "Suporte Netplay (ponto-a-ponto)" + "Suporte de jogo em rede (ponto-a-ponto)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, @@ -2848,7 +2852,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, - "Captura de Tela" + "Capturas de Tela" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, @@ -3048,7 +3052,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, - "Utilizar Modo de Tela Cheia" + "Iniciar em Modo de Tela Cheia" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, @@ -3290,6 +3294,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, "Dot-Art" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_AUTOMATIC, + "Automático" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, "Tema de Cor do Menu" @@ -3388,7 +3396,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, - "Exibir Aba de Netplay" + "Exibir Aba de Jogo em Rede" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_LAYOUT, @@ -3408,7 +3416,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, - "Habilitar ou desabilitar conquistas. Para mais informações, visite http://retroachievements.org" + "Habilita ou desabilita as conquistas. Para mais informações, visite http://retroachievements.org" ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, @@ -3416,107 +3424,107 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, - "Habilitar ou desabilitar Estado de Jogo, Trapaças, Rebobinamento, Avanço Rápido, Pausa e Câmera Lenta para todos os jogos." + "Habilita ou desabilita Estado de Jogo, Trapaças, Rebobinamento, Avanço Rápido, Pausa e Câmera Lenta para todos os jogos." ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_LEADERBOARDS_ENABLE, - "Habilitar ou desabilitar tabelas de classificação no jogo. Não tem efeito se o modo Hardcore estiver desativado." + "Habilita ou desabilita tabelas de classificação no jogo. Não tem efeito se o modo Hardcore estiver desativado." ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_BADGES_ENABLE, - "Habilitar ou desabilitar a exibição de insígnia na Lista de Conquistas." + "Habilita ou desabilita a exibição de insígnia na Lista de Conquistas." ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE, - "Habilitar ou desabilitar detalhes das conquistas na tela." + "Habilita ou desabilita detalhes das conquistas na tela." ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_AUTO_SCREENSHOT, - "Obter automaticamente uma captura de tela quando uma conquista é acionada." + "Obtém automaticamente uma captura de tela quando uma conquista é acionada." ) MSG_HASH( MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, - "Alterar os drivers utilizados pelo sistema." + "Altera os drivers utilizados pelo sistema." ) MSG_HASH( MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "Alterar as configurações de conquistas." + "Altera as configurações de conquistas." ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_SETTINGS, - "Alterar as configurações de núcleo." + "Altera as configurações de núcleo." ) MSG_HASH( MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, - "Alterar as configurações de gravação." + "Altera as configurações de gravação." ) MSG_HASH( MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, - "Alterar as configurações de Transparência e Transparência de teclado, e as configurações de notificação na tela." + "Altera as configurações de Transparência e Transparência de teclado, e as configurações de notificação na tela." ) MSG_HASH( MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, - "Alterar as configurações de Rebobinamento, Avanço Rápido e Câmera Lenta." + "Altera as configurações de Rebobinamento, Avanço Rápido e Câmera Lenta." ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVING_SETTINGS, - "Alterar as configurações de salvamento." + "Altera as configurações de salvamento." ) MSG_HASH( MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, - "Alterar as configurações de registro de eventos." + "Altera as configurações de registro de eventos." ) MSG_HASH( MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, - "Alterar as configurações da interface de usuário." + "Altera as configurações da interface de usuário." ) MSG_HASH( MENU_ENUM_SUBLABEL_USER_SETTINGS, - "Alterar as configurações de conta, nome de usuário e idioma." + "Altera as configurações de conta, nome de usuário e idioma." ) MSG_HASH( MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, - "Alterar as configurações de privacidade." + "Altera as configurações de privacidade." ) MSG_HASH( MENU_ENUM_SUBLABEL_MIDI_SETTINGS, - "Alterar as Configurações de MIDI." + "Altera as configurações de MIDI." ) MSG_HASH( MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, - "Alterar os diretórios padrão onde os arquivos estão localizados." + "Altera os diretórios padrões onde os arquivos estão localizados." ) MSG_HASH( MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, - "Alterar as configurações de lista de reprodução." + "Altera as configurações de lista de reprodução." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, - "Configurar as configurações de servidor e rede." + "Ajusta as configurações de servidor e rede." ) MSG_HASH( MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, - "Analisar conteúdo e adicionar na base de dados." + "Analisa o conteúdo e adiciona na base de dados." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, - "Alterar as configurações de saída de áudio." + "Altera as configurações de saída de áudio." ) MSG_HASH( MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, - "Habilitar ou desabilitar o bluetooth." + "Habilita ou desabilita o bluetooth." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, - "Salvar as alterações nos arquivos de configuração ao sair." + "Salva as alterações nos arquivos de configuração ao sair." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, - "Alterar as definições padrão para os arquivos de configuração." + "Altera as definições padrões para os arquivos de configuração." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, - "Gerenciar e criar arquivos de configuração." + "Gerencia e cria arquivos de configuração." ) MSG_HASH( MENU_ENUM_SUBLABEL_CPU_CORES, @@ -3524,11 +3532,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_FPS_SHOW, - "Exibir a taxa atual de quadros por segundo na tela." + "Exibe a taxa atual de quadros por segundo na tela." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, - "Ajustar configurações das teclas de atalho." + "Ajusta as configurações das teclas de atalho." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, @@ -3536,39 +3544,39 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_SETTINGS, - "Alterar as configurações de Joypad, teclado e Mouse." + "Altera as configurações de Joypad, Teclado e Mouse." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, - "Configurar os controles para este usuário." + "Configura os controles para este usuário." ) MSG_HASH( MENU_ENUM_SUBLABEL_LATENCY_SETTINGS, - "Altere as configurações relacionadas a vídeo, áudio e latência dos comandos." + "Altera as configurações relacionadas a vídeo, áudio e latência dos comandos." ) MSG_HASH( MENU_ENUM_SUBLABEL_LOG_VERBOSITY, - "Habilitar ou desabilitar registro de eventos no terminal." + "Habilita ou desabilita o registro de eventos no terminal." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY, - "Juntar-se ou hospedar uma sessão de Netplay." + "Juntar-se ou hospedar uma sessão de jogo em rede." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, - "Procurar por e conectar aos hospedeiros de Netplay na rede local." + "Procura e conecta aos hospedeiros de jogo em rede na rede local." ) MSG_HASH( MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Exibir informações de núcleo, rede e sistema." + "Exibe informações de núcleo, rede e sistema." ) MSG_HASH( MENU_ENUM_SUBLABEL_ONLINE_UPDATER, - "Baixar complementos, componentes e conteúdo para o RetroArch." + "Baixe complementos, componentes e conteúdo para o RetroArch." ) MSG_HASH( MENU_ENUM_SUBLABEL_SAMBA_ENABLE, - "Habilitar ou desabilitar compartilhamento de pastas na rede." + "Habilita ou desabilita o compartilhamento de pastas na rede." ) MSG_HASH( MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, @@ -3576,27 +3584,27 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, - "Exibir arquivos/diretórios ocultos no navegador de arquivos." + "Exibe arquivos/diretórios ocultos no navegador de arquivos." ) MSG_HASH( MENU_ENUM_SUBLABEL_SSH_ENABLE, - "Habilitar ou desabilitar acesso remoto à linha de comando." + "Habilita ou desabilita o acesso remoto à linha de comando." ) MSG_HASH( MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, - "Prevenir que o protetor de tela do seu sistema seja ativado." + "Evita que a proteção de tela do seu sistema seja ativada." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, - "Definir o tamanho da janela em relação ao tamanho da janela de exibição do núcleo. Como alternativa, você pode definir uma largura e altura de janela abaixo para um tamanho de janela fixo." + "Define o tamanho da janela em relação ao tamanho da janela de exibição do núcleo. Como alternativa, você pode definir uma largura e altura de janela abaixo para um tamanho de janela fixo." ) MSG_HASH( MENU_ENUM_SUBLABEL_USER_LANGUAGE, - "Definir o idioma da interface." + "Define o idioma da interface." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Inserir um quadro opaco entre quadros. Útil para usuários com telas de 120Hz que desejam jogar conteúdos em 60Hz para eliminar efeito de fantasma." + "Insere um quadro opaco entre os quadros. Útil para usuários com telas de 120Hz que desejam jogar conteúdos em 60Hz para eliminar efeito de fantasma." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, @@ -3604,7 +3612,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, - "Definir quantos quadros a CPU pode rodar à frente da GPU quando utilizado o recurso 'Sincronia Rígida de GPU'." + "Define quantos quadros a CPU pode rodar à frente da GPU quando utilizado o recurso 'Sincronia Rígida de GPU'." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, @@ -3612,7 +3620,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, - "Seleciona qual tela de exibição a ser usada." + "Selecione qual tela de exibição a ser usada." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, @@ -3624,11 +3632,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, - "Alterar as configurações de saída de vídeo." + "Altera as configurações de saída de vídeo." ) MSG_HASH( MENU_ENUM_SUBLABEL_WIFI_SETTINGS, - "Analisar por redes sem fio e estabelecer uma conexão." + "Analisa redes sem fio e estabelecer uma conexão." ) MSG_HASH( MENU_ENUM_SUBLABEL_HELP_LIST, @@ -3660,11 +3668,11 @@ MSG_HASH( ) MSG_HASH( MSG_AUDIO_MUTED, - "Áudio mudo." + "Sem áudio." ) MSG_HASH( MSG_AUDIO_UNMUTED, - "Áudio mudo desativado." + "Áudio normal." ) MSG_HASH( MSG_AUTOCONFIG_FILE_ERROR_SAVING, @@ -4164,7 +4172,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_FAILED, - "Falha em inicializar o Netplay." + "Falha em inicializar o jogo em rede." ) MSG_HASH( MSG_NO_CONTENT_STARTING_DUMMY_CORE, @@ -4436,7 +4444,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MUTE, - "Áudio mudo/não-mudo." + "Silencia o áudio." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, @@ -4460,7 +4468,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, - "Permitir a qualquer usuário controlar o menu. Se desabilitado, apenas o Usuário 1 poderá controlar o menu." + "Permite a qualquer usuário controlar o menu. Se desabilitado, apenas o Usuário 1 poderá controlar o menu." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_VOLUME, @@ -4632,19 +4640,19 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_LAN_SCAN_COMPLETE, - "Análise de Netplay completa." + "Análise de jogo em rede completa." ) MSG_HASH( MSG_NETPLAY_LAN_SCANNING, - "Analisando por hospedeiros de Netplay..." + "Analisando por hospedeiros de jogo em rede..." ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, - "Pausar o jogo quando a janela do RetroArch não estiver ativa." + "Pausa o jogo quando a janela do RetroArch não está ativa." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, - "Habilitar ou desabilitar composição (Somente no Windows)." + "Ativa ou desativa a composição (Somente no Windows)." ) MSG_HASH( MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, @@ -4660,11 +4668,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, - "Utilizar os mesmos controles para o menu e jogo. Aplica-se ao teclado." + "Utiliza os mesmos controles para o menu e jogo. Aplica-se ao teclado." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, - "Exibir mensagens na tela." + "Exibe as mensagens na tela." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, @@ -4692,7 +4700,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, - "O Netplay irá iniciar quando o conteúdo for carregado." + "O jogo em rede irá iniciar quando o conteúdo for carregado." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, @@ -4756,31 +4764,31 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, - "Insira seu nome de usuário aqui. Isto será utilizado para sessões do Netplay, entre outras coisas." + "Insira seu nome de usuário aqui. Isto será utilizado para sessões do jogo em rede, entre outras coisas." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, - "Capturar a imagem depois que os filtros (mas não os Shaders) forem aplicados. Seu vídeo ficará tão elegante quanto o que você vê na tela." + "Captura a imagem depois que os filtros (mas não os Shaders) forem aplicados. Seu vídeo ficará tão bonito quanto o que você vê na tela." ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, - "Selecionar qual núcleo utilizar." + "Selecione qual núcleo utilizar." ) MSG_HASH( MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, - "Selecionar qual conteúdo iniciar." + "Selecione qual conteúdo iniciar." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, - "Exibir interfaces de rede e endereços de IP associados." + "Exibe as interfaces de rede e endereços de IP associados." ) MSG_HASH( MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, - "Exibir informações específicas do dispositivo." + "Exibe informações específicas do dispositivo." ) MSG_HASH( MENU_ENUM_SUBLABEL_QUIT_RETROARCH, - "Sair do programa." + "Sai do programa." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, @@ -4812,11 +4820,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, - "Ocultar a Transparência enquanto estiver dentro do menu e exibir novamente ao sair." + "Oculta a Transparência enquanto estiver dentro do menu e exibe novamente ao sair." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, - "Exibir comandos de teclado/controle na transparência." + "Exibe comandos de teclado/controle na transparência." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, @@ -4872,7 +4880,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RUN_AHEAD_ENABLED, - "Executar o núcleo lógico um ou mais quadros à frente e carreguar o estado de volta para reduzir o atraso dos controles percebido." + "Executa o núcleo lógico um ou mais quadros à frente e carrega o estado de volta para reduzir o atraso dos controles percebido." ) MSG_HASH( MENU_ENUM_SUBLABEL_RUN_AHEAD_FRAMES, @@ -5024,7 +5032,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, - "Salvar automaticamente o Save RAM não-volátil em um intervalo regular. Isso está desabilitado por padrão, a menos que seja definido de outra forma. O intervalo é medido em segundos. Um valor de 0 desativa o salvamento automático." + "Salva automaticamente o Save RAM não-volátil em um intervalo regular. Isso está desabilitado por padrão, a menos que seja definido de outra forma. O intervalo é medido em segundos. Um valor de 0 desativa o salvamento automático." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, @@ -5044,19 +5052,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_DRIVER, - "Driver de vídeo para usar." + "Driver de vídeo a ser utilizado." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_DRIVER, - "Driver de áudio para usar." + "Driver de áudio a ser utilizado." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_DRIVER, - "Driver de entrada para usar. Dependendo do driver de vídeo, pode forçar um driver de entrada diferente." + "Driver de entrada a ser utilizado. Dependendo do driver de vídeo, pode forçar um driver de entrada diferente." ) MSG_HASH( MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, - "Driver do Joypad para usar." + "Driver do Joypad a ser utilizado." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_DRIVER, @@ -5092,7 +5100,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_WALLPAPER, - "Seleciona uma imagem para definir como plano de fundo do menu." + "Selecione uma imagem para definir como plano de fundo do menu." ) MSG_HASH( MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER, @@ -5124,7 +5132,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_OVERLAY_PRESET, - "Seleciona uma Transparência pelo navegador de arquivos." + "Selecione uma Transparência pelo navegador de arquivos." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, @@ -5136,19 +5144,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, - "Senha para conectar ao hospedeiro de Netplay. Utilizado apenas no modo hospedeiro." + "Senha para conectar ao hospedeiro de jogo em rede. Utilizado apenas no modo hospedeiro." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, - "Anunciar os jogos de Netplay publicamente. Se não for definido, os clientes deverão conectar manualmente em vez de usar o lobby público." + "Anuncia os jogos em rede publicamente. Se não for definido, os clientes deverão conectar manualmente em vez de usar o lobby público." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, - "Senha para conectar ao hospedeiro de Netplay apenas com privilégios de espectador. Utilizado apenas no modo hospedeiro." + "Senha para conectar ao hospedeiro de jogo em rede apenas com privilégios de espectador. Utilizado apenas no modo hospedeiro." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_START_AS_SPECTATOR, - "Define se o Netplay deve iniciar em modo espectador." + "Define se o jogo em rede deve iniciar em modo espectador." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_SLAVES, @@ -5160,11 +5168,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_STATELESS_MODE, - "Define se deve executar o Netplay em modo que não utilize Estados de Jogo. Se definido como verdadeiro, uma rede muito rápida é necessária, mas nenhum rebobinamento é realizado, portanto, não haverá instabilidade no jogo em rede." + "Define se deve executar o jogo em rede em modo que não utilize Estados de Jogo. Se definido como verdadeiro, uma rede muito rápida é necessária, mas nenhum rebobinamento é realizado, portanto, não haverá instabilidade no jogo em rede." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_CHECK_FRAMES, - "Frequência em quadros no qual o Netplay verificará se o hospedeiro e o cliente estão sincronizados." + "Frequência em quadros no qual o jogo em rede verificará se o hospedeiro e o cliente estão sincronizados." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_NAT_TRAVERSAL, @@ -5172,15 +5180,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, - "Habilitar interface de comando stdin." + "Habilita a interface de comando stdin." ) MSG_HASH( MENU_ENUM_SUBLABEL_MOUSE_ENABLE, - "Habilitar controle por Mouse dentro do menu." + "Habilita o controle por Mouse dentro do menu." ) MSG_HASH( MENU_ENUM_SUBLABEL_POINTER_ENABLE, - "Habilitar controle por toque dentro do menu." + "Habilita o controle por toque dentro do menu." ) MSG_HASH( MENU_ENUM_SUBLABEL_THUMBNAILS, @@ -5196,27 +5204,27 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE, - "Exibir data e/ou hora atuais dentro do menu." + "Exibe data e/ou hora atuais dentro do menu." ) MSG_HASH( MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE, - "Exibir o nível de bateria atual dentro do menu." + "Exibe o nível de bateria atual dentro do menu." ) MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_WRAPAROUND, - "Voltar ao início ou final se o limite da lista for alcançado horizontalmente ou verticalmente." + "Volta ao início ou final se o limite da lista for alcançado horizontalmente ou verticalmente." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, - "Habilita o Netplay no modo hospedeiro (servidor)." + "Habilita o jogo em rede no modo hospedeiro (servidor)." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_CLIENT, - "Habilita o Netplay no modo cliente." + "Habilita o jogo em rede no modo cliente." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_DISCONNECT, - "Desconecta de uma conexão de Netplay ativa." + "Desconecta de uma conexão de jogo em rede ativa." ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_DIRECTORY, @@ -5232,15 +5240,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SORT_SAVEFILES_ENABLE, - "Ordenar os Jogos-Salvos em pastas com o nome do núcleo utilizado." + "Ordena os Jogos-Salvos em pastas com o nome do núcleo utilizado." ) MSG_HASH( MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE, - "Ordenar os Estados de Jogo em pastas com o nome do núcleo utilizado." + "Ordena os Estados de Jogo em pastas com o nome do núcleo utilizado." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_REQUEST_DEVICE_I, - "Solicitar jogar com o dispositivo de entrada dado." + "Solicita jogar com o dispositivo de entrada dado." ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, @@ -5256,55 +5264,55 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, - "Analisar por novas salas." + "Analisa novas salas." ) MSG_HASH( MENU_ENUM_SUBLABEL_DELETE_ENTRY, - "Remover esta entrada da coleção." + "Remove esta entrada da coleção." ) MSG_HASH( MENU_ENUM_SUBLABEL_INFORMATION, - "Visualizar mais informações sobre o conteúdo." + "Visualiza mais informações sobre o conteúdo." ) MSG_HASH( MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES, - "Adicionar o item aos seus favoritos." + "Adiciona o item aos seus favoritos." ) MSG_HASH( MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES_PLAYLIST, - "Adicionar o item aos seus favoritos." + "Adiciona o item aos seus favoritos." ) MSG_HASH( MENU_ENUM_SUBLABEL_RUN, - "Iniciar o conteúdo." + "Inicia o conteúdo." ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, - "Ajustar as definições do navegador de arquivos." + "Ajusta as definições do navegador de arquivos." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, - "Habilitar por padrão controles personalizados na inicialização." + "Habilita por padrão controles personalizados na inicialização." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, - "Habilitar por padrão configuração personalizada na inicialização." + "Habilita por padrão configuração personalizada na inicialização." ) MSG_HASH( MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, - "Habilitar por padrão opções de núcleo personalizadas na inicialização." + "Habilita por padrão opções de núcleo personalizadas na inicialização." ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_ENABLE, - "Exibir o nome do núcleo atual dentro do menu." + "Exibe o nome do núcleo atual dentro do menu." ) MSG_HASH( MENU_ENUM_SUBLABEL_DATABASE_MANAGER, - "Visualizar bases de dados." + "Visualiza as bases de dados." ) MSG_HASH( MENU_ENUM_SUBLABEL_CURSOR_MANAGER, - "Visualizar pesquisas anteriores." + "Visualiza as pesquisas anteriores." ) MSG_HASH( MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, @@ -5316,19 +5324,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_LOAD_STATE, - "Carregar um Estado de Jogo do compartimento selecionado atualmente." + "Carrega um Estado de Jogo do compartimento selecionado atualmente." ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVE_STATE, - "Salvar um Estado de Jogo no compartimento selecionado atualmente." + "Salva um Estado de Jogo no compartimento selecionado atualmente." ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME, - "Retomar a execução do conteúdo atual e sair do Menu Rápido." + "Continua a execução do conteúdo atual e sai do Menu Rápido." ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Retomar a execução do conteúdo atual e sair do Menu Rápido." + "Continua a execução do conteúdo atual e sai do Menu Rápido." ) MSG_HASH( MENU_ENUM_SUBLABEL_STATE_SLOT, @@ -5380,23 +5388,23 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, - "Configurar códigos de Trapaça." + "Configura os códigos de Trapaça." ) MSG_HASH( MENU_ENUM_SUBLABEL_SHADER_OPTIONS, - "Configurar Shader para realçar a aparência da imagem." + "Configura o Shader para realçar a aparência da imagem." ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Alterar os controles para o conteúdo que está sendo executado." + "Altera os controles para o conteúdo que está sendo executado." ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Alterar as opções para o conteúdo que está sendo executado." + "Altera as opções para o conteúdo que está sendo executado." ) MSG_HASH( MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, - "Exibir as configurações avançadas para usuários experientes (oculto por padrão)." + "Exibe as configurações avançadas para usuários experientes (oculto por padrão)." ) MSG_HASH( MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, @@ -5404,7 +5412,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, - "Permitir que o usuário possa remover itens das coleções." + "Permite que o usuário possa remover itens das coleções." ) MSG_HASH( MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, @@ -5432,11 +5440,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, - "O número de quadros de latência de entrada para o Netplay utilizar para mascarar a latência da rede. Reduz a oscilação e torna o Netplay menos intensivo para a CPU, ao custo de atraso perceptível na entrada." + "O número de quadros de latência de entrada para o jogo em rede utilizar para mascarar a latência da rede. Reduz a oscilação e torna o jogo em rede menos intensivo para a CPU, ao custo de atraso perceptível na entrada." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, - "O intervalo de quadros de latência de entrada que pode ser utilizado para mascarar a latência da rede. Reduz a oscilação e torna o Netplay menos intensivo para a CPU, ao custo de atraso imprevisível na entrada." + "O intervalo de quadros de latência de entrada que pode ser utilizado para mascarar a latência da rede. Reduz a oscilação e torna o jogo em rede menos intensivo para a CPU, ao custo de atraso imprevisível na entrada." ) MSG_HASH( MENU_ENUM_SUBLABEL_DISK_CYCLE_TRAY_STATUS, @@ -5444,7 +5452,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_DISK_INDEX, - "Mudar o índice do disco." + "Mude o índice do disco." ) MSG_HASH( MENU_ENUM_SUBLABEL_DISK_OPTIONS, @@ -5460,7 +5468,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VRR_RUNLOOP_ENABLE, - "Não desviar dos tempos solicitado pelo núcleo. Usar com telas de Taxa de Atualização Variável, G-Sync, FreeSync." + "Não desvia dos tempos solicitados pelo núcleo. Use com telas de Taxa de Atualização Variável, G-Sync, FreeSync." ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_LAYOUT, @@ -5468,79 +5476,79 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_THEME, - "Selecionar um tema diferente para os ícones. As alterações terão efeito após reiniciar o programa." + "Selecione um tema diferente para os ícones. As alterações terão efeito após reiniciar o programa." ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE, - "Habilitar as sombras para todos os ícones. Isto terá um pequeno impacto no desempenho." + "Habilite as sombras para todos os ícones. Isto terá um pequeno impacto no desempenho." ) MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME, - "Selecionar um tema de gradiente de cor de plano de fundo diferente." + "Selecione um tema de gradiente de cor de plano de fundo diferente." ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY, - "Modificar a opacidade do plano de fundo." + "Modifica a opacidade do plano de fundo." ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_MENU_COLOR_THEME, - "Selecionar um tema de gradiente de cor de plano de fundo diferente." + "Selecione um tema de gradiente de cor de plano de fundo diferente." ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, - "Selecionar um efeito de plano de fundo animado. Pode exigir mais processamento da GPU dependendo do efeito. Se o desempenho for insatisfatório, desligue este efeito ou reverta para um efeito mais simples." + "Selecione um efeito de plano de fundo animado. Pode exigir mais processamento da GPU dependendo do efeito. Se o desempenho for insatisfatório, desligue este efeito ou reverta para um efeito mais simples." ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_FONT, - "Selecionar uma fonte principal diferente para ser usada pelo menu." + "Selecione uma fonte principal diferente para ser usada pelo menu." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_FAVORITES, - "Exibir a aba de favoritos dentro do menu principal." + "Exibe a aba de favoritos dentro do menu principal." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, - "Exibir a aba de imagem dentro do menu principal." + "Exibe a aba de imagem dentro do menu principal." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, - "Exibir a aba de música dentro do menu principal." + "Exibe a aba de música dentro do menu principal." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, - "Exibir a aba de vídeo dentro do menu principal." + "Exibe a aba de vídeo dentro do menu principal." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, - "Exibir a aba de Netplay dentro do menu principal." + "Exibe a aba de jogo em rede dentro do menu principal." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS, - "Mostrar a aba de configurações dentro do menu principal." + "Exibe a aba de configurações dentro do menu principal." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_HISTORY, - "Mostrar a aba de histórico recente dentro do menu principal." + "Exibe a aba de histórico recente dentro do menu principal." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, - "Mostrar a aba de importação de conteúdo dentro do menu principal." + "Exibe a aba de importação de conteúdo dentro do menu principal." ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Exibir abas da lista de reprodução dentro do menu principal." + "Exibe abas da lista de reprodução dentro do menu principal." ) MSG_HASH( MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, - "Exibir a tela inicial no menu. É automaticamente definido como falso após o programa iniciar pela primeira vez." + "Exibe a tela inicial no menu. É automaticamente definido como falso após o programa iniciar pela primeira vez." ) MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, - "Modificar a opacidade do gráfico do cabeçalho." + "Modifica a opacidade do gráfico do cabeçalho." ) MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, - "Modificar a opacidade do gráfico do rodapé." + "Modifica a opacidade do gráfico do rodapé." ) MSG_HASH( MENU_ENUM_SUBLABEL_DPI_OVERRIDE_ENABLE, @@ -5548,15 +5556,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_DPI_OVERRIDE_VALUE, - "Definir o tamanho do dimensionamento personalizado aqui. OBS: Você deve habilitar a função 'Redefinição de DPI' para que este dimensionamento tenha efeito." + "Define o tamanho do dimensionamento personalizado aqui. OBS: Você deve habilitar a função 'Redefinição de DPI' para que este dimensionamento tenha efeito." ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, - "Salvar todos os arquivos baixados neste diretório." + "Salva todos os arquivos baixados neste diretório." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_REMAPPING_DIRECTORY, - "Salvar todos os controles remapeados neste diretório." + "Salva todos os controles remapeados neste diretório." ) MSG_HASH( MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, @@ -5572,7 +5580,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PLAYLIST_DIRECTORY, - "Salvar todas as coleções neste diretório." + "Salva todas as coleções neste diretório." ) MSG_HASH( MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, @@ -5592,11 +5600,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVEFILE_DIRECTORY, - "Salvar todos os Jogos-Salvos neste diretório. Se não for definido, tentaremos salvar dentro do diretório de trabalho do arquivo." + "Salva todos os Jogos-Salvos neste diretório. Se não for definido, tentaremos salvar dentro do diretório de trabalho do arquivo." ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_DIRECTORY, - "Salvar todos os Estados de Jogo neste diretório. Se não for definido, tentaremos salvar dentro do diretório de trabalho do arquivo." + "Salva todos os Estados de Jogo neste diretório. Se não for definido, tentaremos salvar dentro do diretório de trabalho do arquivo." ) MSG_HASH( MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, @@ -5632,7 +5640,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_PATH, - "Selecionar uma fonte diferente para as notificações na tela." + "Selecione uma fonte diferente para as notificações na tela." ) MSG_HASH( MENU_ENUM_SUBLABEL_SHADER_APPLY_CHANGES, @@ -5700,11 +5708,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SETTINGS, - "Acessar rapidamente todas as configurações relevantes ao jogo." + "Acesse rapidamente todas as configurações relevantes ao jogo." ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFORMATION, - "Visualizar informações sobre a aplicação/núcleo." + "Visualiza as informações sobre a aplicação/núcleo." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO, @@ -5712,11 +5720,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "Personalizar a altura da janela de exibição que é usada se a Proporção de Tela estiver definida como 'Personalizada'." + "Personaliza a altura da janela de exibição que é usada se a Proporção de Tela estiver definida como 'Personalizada'." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "Personalizar a largura da janela de exibição que é usada se a Proporção de Tela estiver definida como 'Personalizada'." + "Personaliza a largura da janela de exibição que é usada se a Proporção de Tela estiver definida como 'Personalizada'." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, @@ -5732,7 +5740,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, - "Encaminhar conexões do Netplay através de um servidor 'homem no meio' (MITM). Útil se o hospedeiro estiver atrás de um firewall ou tiver problemas de NAT/UPnP." + "Encaminha conexões de jogo em rede através de um servidor 'homem no meio' (MITM). Útil se o hospedeiro estiver atrás de um firewall ou tiver problemas de NAT/UPnP." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER, @@ -5776,11 +5784,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, - "Mixer de Áudio Mudo" + "Silenciar Mixer de Áudio" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, - "Mixer de áudio mudo/não-mudo." + "Silencia o mixer de áudio" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_ONLINE_UPDATER, @@ -5796,7 +5804,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_VIEWS_SETTINGS, - "Exibir elementos na tela de menu." + "Exibe elementos na tela de menu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, @@ -5896,7 +5904,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, - "Permita que o usuário renomeie os itens nas coleções." + "Permite que o usuário renomeie os itens nas coleções." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, @@ -6111,7 +6119,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_KIOSK_MODE_PASSWORD, - "Fornecer uma senha ao habilitar o Modo Quiosque tornando possível desabilitar mais tarde a partir do menu, indo para o Menu Principal, selecionando Desabilitar o Modo Quiosque e inserindo a senha." + "Fornece uma senha ao habilitar o Modo Quiosque tornando possível desabilitar mais tarde a partir do menu, indo para o Menu Principal, selecionando Desabilitar o Modo Quiosque e inserindo a senha." ) MSG_HASH( MSG_INPUT_KIOSK_MODE_PASSWORD, @@ -6211,7 +6219,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STATISTICS_SHOW, - "Mostrar estatísticas técnicas na tela." + "Exibe estatísticas técnicas na tela." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_ENABLE, @@ -6271,7 +6279,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_ENABLE_MENU, - "Ativar ou desativar o som do menu." + "Ativa ou desativa o som do menu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_SETTINGS, @@ -6279,7 +6287,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_SETTINGS, - "Visualizar e/ou modificar as configurações do mixer de áudio." + "Visualiza e/ou modifica as configurações do mixer de áudio." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_INFO, @@ -6703,7 +6711,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_POWER_MANAGEMENT_SETTINGS, - "Altere as configurações de gerenciamento de energia." + "Altera as configurações de gerenciamento de energia." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SUSTAINED_PERFORMANCE_MODE, @@ -7377,3 +7385,13 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, "Restaurar Parâmetro" ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, + "Baixar miniaturas") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, + "Um download já está em progresso.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, + "Iniciar na lista de reprodução:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, + "Baixar Todas as Miniaturas") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, + "Miniaturas baixadas com sucesso.") From 38f3d06d08839e1aa10e5368fb1e828b41cf3ed3 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 27 Aug 2018 17:56:53 -0400 Subject: [PATCH 161/182] Qt: use C locale for numbers, otherwise slang shaders can break --- ui/drivers/qt/ui_qt_application.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ui/drivers/qt/ui_qt_application.cpp b/ui/drivers/qt/ui_qt_application.cpp index ff36e92b59..3a45561c53 100644 --- a/ui/drivers/qt/ui_qt_application.cpp +++ b/ui/drivers/qt/ui_qt_application.cpp @@ -25,6 +25,9 @@ extern "C" { #include "../../../frontend/frontend.h" #include "../../../tasks/tasks_internal.h" #include +#ifdef Q_OS_UNIX +#include +#endif } #include "../ui_qt.h" @@ -127,6 +130,9 @@ static void* ui_application_qt_initialize(void) ui_application.app->setApplicationVersion(PACKAGE_VERSION); ui_application.app->connect(ui_application.app, SIGNAL(lastWindowClosed()), appHandler, SLOT(onLastWindowClosed())); +#ifdef Q_OS_UNIX + setlocale(LC_NUMERIC, "C"); +#endif { /* Can't declare the pixmap at the top, because: "QPixmap: Must construct a QGuiApplication before a QPixmap" */ QImage iconImage(16, 16, QImage::Format_ARGB32); From d8913d5d3aad1f21a35af6b132d998ddb56273d7 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 27 Aug 2018 23:29:44 -0400 Subject: [PATCH 162/182] Qt: add right-click for playlists to download thumbnails for the current entries --- Makefile.common | 3 +- griffin/griffin_cpp.cpp | 1 + intl/msg_hash_ja.h | 6 + intl/msg_hash_us.h | 6 + msg_hash.h | 3 + ui/drivers/qt/playlist.cpp | 30 +- ui/drivers/qt/playlistthumbnaildownload.cpp | 332 ++++++++++++++++++++ ui/drivers/qt/thumbnaildownload.cpp | 2 +- ui/drivers/qt/thumbnailpackdownload.cpp | 1 + ui/drivers/qt/ui_qt_window.cpp | 25 ++ ui/drivers/ui_qt.h | 18 ++ 11 files changed, 418 insertions(+), 9 deletions(-) create mode 100644 ui/drivers/qt/playlistthumbnaildownload.cpp diff --git a/Makefile.common b/Makefile.common index 93a2856104..d32bea96df 100644 --- a/Makefile.common +++ b/Makefile.common @@ -353,7 +353,8 @@ OBJ += ui/drivers/ui_qt.o \ ui/drivers/qt/playlist.o \ ui/drivers/qt/updateretroarch.o \ ui/drivers/qt/thumbnaildownload.o \ - ui/drivers/qt/thumbnailpackdownload.o + ui/drivers/qt/thumbnailpackdownload.o \ + ui/drivers/qt/playlistthumbnaildownload.o MOC_HEADERS += ui/drivers/ui_qt.h \ ui/drivers/qt/ui_qt_load_core_window.h \ diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index 47f25ab447..56f15070f7 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -51,6 +51,7 @@ UI #include "../ui/drivers/qt/updateretroarch.cpp" #include "../ui/drivers/qt/thumbnaildownload.cpp" #include "../ui/drivers/qt/thumbnailpackdownload.cpp" +#include "../ui/drivers/qt/playlistthumbnaildownload.cpp" #endif /*============================================================ diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index d71ea6ff28..ed2daaa004 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3796,5 +3796,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, "起動時に表示するプレイリスト:") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, "すべてのサムネイルをダウンロード") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_ENTIRE_SYSTEM, + "システムのすべて") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_THIS_PLAYLIST, + "このプレイリスト") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, "サムネイルのダウンロードが成功しました。") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_PLAYLIST_THUMBNAIL_PROGRESS, + "成功した数: %1 失敗した数: %2") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index b0c9290fa0..38f6bade70 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -7394,5 +7394,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, "Start on playlist:") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, "Download All Thumbnails") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_ENTIRE_SYSTEM, + "Entire System") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_THIS_PLAYLIST, + "This Playlist") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, "Thumbnails downloaded successfully.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_PLAYLIST_THUMBNAIL_PROGRESS, + "Succeeded: %1 Failed: %2") diff --git a/msg_hash.h b/msg_hash.h index 3e1cd59d77..10661c8675 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -2008,7 +2008,10 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_ENTIRE_SYSTEM, + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_THIS_PLAYLIST, MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_PLAYLIST_THUMBNAIL_PROGRESS, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp index af8bf6bc31..0e2099fb71 100644 --- a/ui/drivers/qt/playlist.cpp +++ b/ui/drivers/qt/playlist.cpp @@ -374,10 +374,12 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) QScopedPointer menu; QScopedPointer associateMenu; QScopedPointer hiddenPlaylistsMenu; + QScopedPointer downloadAllThumbnailsMenu; QScopedPointer hideAction; QScopedPointer newPlaylistAction; QScopedPointer deletePlaylistAction; - QScopedPointer downloadAllThumbnailsAction; + QScopedPointer downloadAllThumbnailsEntireSystemAction; + QScopedPointer downloadAllThumbnailsThisPlaylistAction; QPointer selectedAction; QPoint cursorPos = QCursor::pos(); QListWidgetItem *selectedItem = m_listWidget->itemAt(m_listWidget->viewport()->mapFromGlobal(cursorPos)); @@ -530,9 +532,16 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) if (!specialPlaylist) { - downloadAllThumbnailsAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS), this)); + downloadAllThumbnailsMenu.reset(new QMenu(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS), this)); + downloadAllThumbnailsMenu->setObjectName("downloadAllThumbnailsMenu"); - menu->addAction(downloadAllThumbnailsAction.data()); + downloadAllThumbnailsThisPlaylistAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_THIS_PLAYLIST), downloadAllThumbnailsMenu.data())); + downloadAllThumbnailsEntireSystemAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_ENTIRE_SYSTEM), downloadAllThumbnailsMenu.data())); + + downloadAllThumbnailsMenu->addAction(downloadAllThumbnailsThisPlaylistAction.data()); + downloadAllThumbnailsMenu->addAction(downloadAllThumbnailsEntireSystemAction.data()); + + menu->addMenu(downloadAllThumbnailsMenu.data()); } selectedAction = menu->exec(cursorPos); @@ -633,12 +642,19 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) } } } - else if (selectedItem && !specialPlaylist && selectedAction == downloadAllThumbnailsAction.data()) + else if (selectedItem && !specialPlaylist && selectedAction->parent() == downloadAllThumbnailsMenu.data()) { - int row = m_listWidget->row(selectedItem); + if (selectedAction == downloadAllThumbnailsEntireSystemAction.data()) + { + int row = m_listWidget->row(selectedItem); - if (row >= 0) - downloadAllThumbnails(currentPlaylistFileInfo.completeBaseName()); + if (row >= 0) + downloadAllThumbnails(currentPlaylistFileInfo.completeBaseName()); + } + else if (selectedAction == downloadAllThumbnailsThisPlaylistAction.data()) + { + downloadPlaylistThumbnails(currentPlaylistPath); + } } setCoreActions(); diff --git a/ui/drivers/qt/playlistthumbnaildownload.cpp b/ui/drivers/qt/playlistthumbnaildownload.cpp new file mode 100644 index 0000000000..985e7bb283 --- /dev/null +++ b/ui/drivers/qt/playlistthumbnaildownload.cpp @@ -0,0 +1,332 @@ +#include +#include +#include + +#include "../ui_qt.h" + +extern "C" { +#include +#include +#include +#include "../../../tasks/tasks_internal.h" +#include "../../../verbosity.h" +#include "../../../config.def.h" +#include "../../../configuration.h" +#include "../../../version.h" +} + +#define USER_AGENT "RetroArch-WIMP/" PACKAGE_VERSION +#define PARTIAL_EXTENSION ".partial" +#define THUMBNAIL_URL_HEADER "https://github.com/libretro-thumbnails/" +#define THUMBNAIL_URL_BRANCH "/blob/master/" +#define THUMBNAIL_IMAGE_EXTENSION ".png" +#define THUMBNAIL_URL_FOOTER THUMBNAIL_IMAGE_EXTENSION "?raw=true" + +void MainWindow::onPlaylistThumbnailDownloadNetworkError(QNetworkReply::NetworkError /*code*/) +{ +} + +void MainWindow::onPlaylistThumbnailDownloadNetworkSslErrors(const QList &errors) +{ + QNetworkReply *reply = m_playlistThumbnailDownloadReply.data(); + int i; + + if (!reply) + return; + + for (i = 0; i < errors.count(); i++) + { + const QSslError &error = errors.at(i); + QString string = QString("Ignoring SSL error code ") + QString::number(error.error()) + ": " + error.errorString(); + QByteArray stringArray = string.toUtf8(); + const char *stringData = stringArray.constData(); + RARCH_ERR("[Qt]: %s\n", stringData); + } + + /* ignore all SSL errors for now, like self-signed, expired etc. */ + reply->ignoreSslErrors(); +} + +void MainWindow::onPlaylistThumbnailDownloadCanceled() +{ + m_playlistThumbnailDownloadProgressDialog->cancel(); +} + +void MainWindow::onPlaylistThumbnailDownloadFinished() +{ + QString playlistPath; + QNetworkReply *reply = m_playlistThumbnailDownloadReply.data(); + QNetworkReply::NetworkError error; + int code; + + if (!reply) + return; + + playlistPath = reply->property("playlist").toString(); + + error = reply->error(); + code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (m_playlistThumbnailDownloadFile.isOpen()) + m_playlistThumbnailDownloadFile.close(); + + if (code != 200) + { + QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + + if (!redirectUrl.isEmpty()) + { + QByteArray redirectUrlArray = redirectUrl.toString().toUtf8(); + const char *redirectUrlData = redirectUrlArray.constData(); + + /*RARCH_LOG("[Qt]: Thumbnail download got redirect with HTTP code %d: %s\n", code, redirectUrlData);*/ + + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + + downloadNextPlaylistThumbnail(reply->property("system").toString(), reply->property("title").toString(), reply->property("type").toString(), redirectUrl); + + return; + } + else + { + m_playlistThumbnailDownloadFile.remove(); + + m_failedThumbnails++; + + /*emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": HTTP Code " + QString::number(code)); + + RARCH_ERR("[Qt]: Thumbnail download failed with HTTP status code: %d\n", code); + + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + + return;*/ + } + } + + if (error == QNetworkReply::NoError) + { + int index = m_playlistThumbnailDownloadFile.fileName().lastIndexOf(PARTIAL_EXTENSION); + QString newFileName = m_playlistThumbnailDownloadFile.fileName().left(index); + QFile newFile(newFileName); + + /* rename() requires the old file to be deleted first if it exists */ + if (newFile.exists() && !newFile.remove()) + { + m_failedThumbnails++; + RARCH_ERR("[Qt]: Thumbnail download finished, but old file could not be deleted.\n"); + } + else + { + if (m_playlistThumbnailDownloadFile.rename(newFileName)) + { + /*RARCH_LOG("[Qt]: Thumbnail download finished successfully.\n");*/ + m_downloadedThumbnails++; + } + else + { + /*RARCH_ERR("[Qt]: Thumbnail download finished, but temp file could not be renamed.\n"); + emit showErrorMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE));*/ + m_failedThumbnails++; + } + } + } + else + { + /*QByteArray errorArray = reply->errorString().toUtf8(); + const char *errorData = errorArray.constData();*/ + + m_playlistThumbnailDownloadFile.remove(); + + m_failedThumbnails++; + + /*RARCH_ERR("[Qt]: Thumbnail download ended prematurely: %s\n", errorData); + emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": Code " + QString::number(code) + ": " + errorData);*/ + } + + if (m_pendingPlaylistThumbnails.count() > 0) + { + QHash nextThumbnail = m_pendingPlaylistThumbnails.takeAt(0); + ViewType viewType = getCurrentViewType(); + + if (viewType == VIEW_TYPE_ICONS) + emit gridItemChanged(reply->property("title").toString()); + + downloadNextPlaylistThumbnail(nextThumbnail.value("db_name"), nextThumbnail.value("label_noext"), nextThumbnail.value("type")); + } + else + { + RARCH_LOG("[Qt]: Playlist thumbnails finished downloading.\n"); + /* update thumbnail */ + emit itemChanged(); + } + + reply->disconnect(); + reply->close(); + reply->deleteLater(); +} + +void MainWindow::onPlaylistThumbnailDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + QNetworkReply *reply = m_playlistThumbnailDownloadReply.data(); + int progress = (bytesReceived / (float)bytesTotal) * 100.0f; + + if (!reply) + return; +} + +void MainWindow::onPlaylistThumbnailDownloadReadyRead() +{ + QNetworkReply *reply = m_playlistThumbnailDownloadReply.data(); + + if (!reply) + return; + + m_playlistThumbnailDownloadFile.write(reply->readAll()); +} + +void MainWindow::downloadNextPlaylistThumbnail(QString system, QString title, QString type, QUrl url) +{ + QString systemUnderscore = system; + QString urlString; + QNetworkReply *reply = NULL; + QNetworkRequest request; + settings_t *settings = config_get_ptr(); + + if (!settings) + return; + + systemUnderscore = systemUnderscore.replace(" ", "_"); + + urlString = QString(THUMBNAIL_URL_HEADER) + systemUnderscore + THUMBNAIL_URL_BRANCH + type + "/" + title + THUMBNAIL_URL_FOOTER; + + if (url.isEmpty()) + url = urlString; + + request.setUrl(url); + + if (m_playlistThumbnailDownloadFile.isOpen()) + { + RARCH_ERR("[Qt]: File is already open.\n"); + return; + } + else + { + QString dirString = QString(settings->paths.directory_thumbnails); + QString fileName = dirString + "/" + system + "/" + type + "/" + title + THUMBNAIL_IMAGE_EXTENSION + PARTIAL_EXTENSION; + QByteArray fileNameArray = fileName.toUtf8(); + QDir dir; + const char *fileNameData = fileNameArray.constData(); + + dir.mkpath(dirString + "/" + system + "/" + THUMBNAIL_BOXART); + dir.mkpath(dirString + "/" + system + "/" + THUMBNAIL_SCREENSHOT); + dir.mkpath(dirString + "/" + system + "/" + THUMBNAIL_TITLE); + + m_playlistThumbnailDownloadFile.setFileName(fileName); + + if (!m_playlistThumbnailDownloadFile.open(QIODevice::WriteOnly)) + { + m_playlistThumbnailDownloadProgressDialog->cancel(); + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Could not open file for writing: %s\n", fileNameData); + return; + } + } + + /*RARCH_LOG("[Qt]: Starting thumbnail download...\n"); + RARCH_LOG("[Qt]: Downloading URL %s\n", urlData);*/ + + request.setHeader(QNetworkRequest::UserAgentHeader, USER_AGENT); + + m_playlistThumbnailDownloadReply = m_networkManager->get(request); + + reply = m_playlistThumbnailDownloadReply.data(); + reply->setProperty("system", system); + reply->setProperty("title", title); + reply->setProperty("type", type); + + /* make sure any previous connection is removed first */ + disconnect(m_playlistThumbnailDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); + disconnect(m_playlistThumbnailDownloadProgressDialog, SIGNAL(canceled()), m_playlistThumbnailDownloadProgressDialog, SLOT(cancel())); + connect(m_playlistThumbnailDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); + connect(m_playlistThumbnailDownloadProgressDialog, SIGNAL(canceled()), m_playlistThumbnailDownloadProgressDialog, SLOT(cancel())); + + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onPlaylistThumbnailDownloadNetworkError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(sslErrors(const QList&)), this, SLOT(onPlaylistThumbnailDownloadNetworkSslErrors(const QList&))); + connect(reply, SIGNAL(finished()), this, SLOT(onPlaylistThumbnailDownloadFinished())); + connect(reply, SIGNAL(readyRead()), this, SLOT(onPlaylistThumbnailDownloadReadyRead())); + connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onPlaylistThumbnailDownloadProgress(qint64, qint64))); + + m_playlistThumbnailDownloadProgressDialog->setValue(m_playlistThumbnailDownloadProgressDialog->maximum() - m_pendingPlaylistThumbnails.count()); + + { + QString labelText = QString(msg_hash_to_str(MSG_DOWNLOADING)) + "...\n"; + + labelText += QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_PLAYLIST_THUMBNAIL_PROGRESS)).arg(m_downloadedThumbnails).arg(m_failedThumbnails); + + m_playlistThumbnailDownloadProgressDialog->setLabelText(labelText); + } +} + +void MainWindow::downloadPlaylistThumbnails(QString playlistPath) +{ + QFile playlistFile(playlistPath); + QString system; + QString title; + QString type; + QVector > playlistItems = getPlaylistItems(playlistPath); + settings_t *settings = config_get_ptr(); + int i; + + if (!settings || !playlistFile.exists()) + return; + + m_pendingPlaylistThumbnails.clear(); + m_downloadedThumbnails = 0; + m_failedThumbnails = 0; + + if (playlistItems.count() == 0) + return; + + for (i = 0; i < playlistItems.count(); i++) + { + const QHash &itemHash = playlistItems.at(i); + QHash hash; + QHash hash2; + QHash hash3; + + hash["db_name"] = itemHash.value("db_name"); + hash["label_noext"] = itemHash.value("label_noext"); + hash["type"] = THUMBNAIL_BOXART; + + hash2 = hash; + hash3 = hash; + + hash2["type"] = THUMBNAIL_SCREENSHOT; + hash3["type"] = THUMBNAIL_TITLE; + + m_pendingPlaylistThumbnails.append(hash); + m_pendingPlaylistThumbnails.append(hash2); + m_pendingPlaylistThumbnails.append(hash3); + } + + m_playlistThumbnailDownloadProgressDialog->setWindowModality(Qt::NonModal); + m_playlistThumbnailDownloadProgressDialog->setMinimumDuration(0); + m_playlistThumbnailDownloadProgressDialog->setRange(0, m_pendingPlaylistThumbnails.count()); + m_playlistThumbnailDownloadProgressDialog->setAutoClose(true); + m_playlistThumbnailDownloadProgressDialog->setAutoReset(true); + m_playlistThumbnailDownloadProgressDialog->setValue(0); + m_playlistThumbnailDownloadProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_DOWNLOADING)) + "..."); + m_playlistThumbnailDownloadProgressDialog->setCancelButtonText(tr("Cancel")); + m_playlistThumbnailDownloadProgressDialog->show(); + + { + QHash firstThumbnail = m_pendingPlaylistThumbnails.takeAt(0); + + /* Start downloading the first thumbnail, the rest will download as each one finishes. */ + downloadNextPlaylistThumbnail(firstThumbnail.value("db_name"), firstThumbnail.value("label_noext"), firstThumbnail.value("type")); + } +} diff --git a/ui/drivers/qt/thumbnaildownload.cpp b/ui/drivers/qt/thumbnaildownload.cpp index ea4ea48839..f70ffcd13a 100644 --- a/ui/drivers/qt/thumbnaildownload.cpp +++ b/ui/drivers/qt/thumbnaildownload.cpp @@ -17,7 +17,6 @@ extern "C" { #define USER_AGENT "RetroArch-WIMP/" PACKAGE_VERSION #define PARTIAL_EXTENSION ".partial" -#define TEMP_EXTENSION ".tmp" #define THUMBNAIL_URL_HEADER "https://github.com/libretro-thumbnails/" #define THUMBNAIL_URL_BRANCH "/blob/master/" #define THUMBNAIL_IMAGE_EXTENSION ".png" @@ -255,6 +254,7 @@ void MainWindow::downloadThumbnail(QString system, QString title, QUrl url) if (!m_thumbnailDownloadFile.open(QIODevice::WriteOnly)) { + m_thumbnailDownloadProgressDialog->cancel(); showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); RARCH_ERR("[Qt]: Could not open file for writing: %s\n", fileNameData); return; diff --git a/ui/drivers/qt/thumbnailpackdownload.cpp b/ui/drivers/qt/thumbnailpackdownload.cpp index 75de1a6016..8fad5548f9 100644 --- a/ui/drivers/qt/thumbnailpackdownload.cpp +++ b/ui/drivers/qt/thumbnailpackdownload.cpp @@ -255,6 +255,7 @@ void MainWindow::downloadAllThumbnails(QString system, QUrl url) if (!m_thumbnailPackDownloadFile.open(QIODevice::WriteOnly)) { + m_thumbnailPackDownloadProgressDialog->cancel(); showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); RARCH_ERR("[Qt]: Could not open file for writing: %s\n", fileNameData); return; diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index c84ae8f878..b0bbc26cce 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -327,6 +327,12 @@ MainWindow::MainWindow(QWidget *parent) : ,m_thumbnailPackDownloadProgressDialog(new QProgressDialog()) ,m_thumbnailPackDownloadFile() ,m_thumbnailPackDownloadReply() + ,m_playlistThumbnailDownloadProgressDialog(new QProgressDialog()) + ,m_playlistThumbnailDownloadFile() + ,m_playlistThumbnailDownloadReply() + ,m_pendingPlaylistThumbnails() + ,m_downloadedThumbnails(0) + ,m_failedThumbnails(0) { settings_t *settings = config_get_ptr(); QDir playlistDir(settings->paths.directory_playlist); @@ -351,6 +357,7 @@ MainWindow::MainWindow(QWidget *parent) : m_updateProgressDialog->cancel(); m_thumbnailDownloadProgressDialog->cancel(); m_thumbnailPackDownloadProgressDialog->cancel(); + m_playlistThumbnailDownloadProgressDialog->cancel(); m_gridProgressWidget = new QWidget(); gridProgressLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PROGRESS), m_gridProgressWidget); @@ -549,6 +556,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_gridLayoutWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onFileDropWidgetContextMenuRequested(const QPoint&))); connect(this, SIGNAL(itemChanged()), this, SLOT(onItemChanged())); + connect(this, SIGNAL(gridItemChanged(QString)), this, SLOT(onGridItemChanged(QString))); connect(this, SIGNAL(gotThumbnailDownload(QString,QString)), this, SLOT(onDownloadThumbnail(QString,QString))); /* make sure these use an auto connection so it will be queued if called from a different thread (some facilities in RA log messages from other threads) */ @@ -639,6 +647,23 @@ QVector > MainWindow::getPlaylists() return playlists; } +void MainWindow::onGridItemChanged(QString title) +{ + int i; + + for (i = 0; i < m_gridItems.count(); i++) + { + const QPointer &item = m_gridItems.at(i); + const QHash &hash = item->hash; + + if (hash.value("label_noext") == title) + { + loadImageDeferred(item.data(), item->widget->property("image_path").toString()); + break; + } + } +} + void MainWindow::onItemChanged() { ViewType viewType = getCurrentViewType(); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 656d5bd967..fd9375ffe6 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -300,6 +300,7 @@ signals: void showInfoMessageDeferred(QString msg); void extractArchiveDeferred(QString path, QString extractionDir, QString tempExtension, retro_task_callback_t cb); void itemChanged(); + void gridItemChanged(QString title); void gotThumbnailDownload(QString system, QString title); public slots: @@ -342,6 +343,8 @@ public slots: void deferReloadShaderParams(); void downloadThumbnail(QString system, QString title, QUrl url = QUrl()); void downloadAllThumbnails(QString system, QUrl url = QUrl()); + void downloadPlaylistThumbnails(QString playlistPath); + void downloadNextPlaylistThumbnail(QString system, QString title, QString type, QUrl url = QUrl()); private slots: void onLoadCoreClicked(const QStringList &extensionFilters = QStringList()); @@ -378,6 +381,7 @@ private slots: void onShowInfoMessage(QString msg); void onContributorsClicked(); void onItemChanged(); + void onGridItemChanged(QString title); int onExtractArchive(QString path, QString extractionDir, QString tempExtension, retro_task_callback_t cb); void onUpdateNetworkError(QNetworkReply::NetworkError code); @@ -402,6 +406,13 @@ private slots: void onThumbnailPackDownloadReadyRead(); void onThumbnailPackDownloadCanceled(); + void onPlaylistThumbnailDownloadNetworkError(QNetworkReply::NetworkError code); + void onPlaylistThumbnailDownloadNetworkSslErrors(const QList &errors); + void onPlaylistThumbnailDownloadFinished(); + void onPlaylistThumbnailDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void onPlaylistThumbnailDownloadReadyRead(); + void onPlaylistThumbnailDownloadCanceled(); + private: void setCurrentCoreLabel(); void getPlaylistFiles(); @@ -489,6 +500,13 @@ private: QFile m_thumbnailPackDownloadFile; QPointer m_thumbnailPackDownloadReply; + QProgressDialog *m_playlistThumbnailDownloadProgressDialog; + QFile m_playlistThumbnailDownloadFile; + QPointer m_playlistThumbnailDownloadReply; + QVector > m_pendingPlaylistThumbnails; + unsigned m_downloadedThumbnails; + unsigned m_failedThumbnails; + protected: void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *event); From 44eb97206ad0ed8815352aa1715a9c8c0779e4fe Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 28 Aug 2018 09:01:25 -0400 Subject: [PATCH 163/182] Qt: fix canceling of thumbnail downloads, use QDir comparison instead of string-based to honor case-insensitivity on Windows --- ui/drivers/qt/playlist.cpp | 3 ++- ui/drivers/qt/playlistthumbnaildownload.cpp | 7 ++++--- ui/drivers/qt/thumbnaildownload.cpp | 2 -- ui/drivers/qt/thumbnailpackdownload.cpp | 2 -- ui/drivers/qt/ui_qt_window.cpp | 10 ++++++++++ ui/drivers/ui_qt.h | 1 + 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp index 0e2099fb71..ce2d1c5eb7 100644 --- a/ui/drivers/qt/playlist.cpp +++ b/ui/drivers/qt/playlist.cpp @@ -467,7 +467,8 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) menu->addMenu(hiddenPlaylistsMenu.data()); - if (currentPlaylistDirPath != playlistDirAbsPath) + /* Don't just compare strings in case there are case differences on Windows that should be ignored. */ + if (QDir(currentPlaylistDirPath) != QDir(playlistDirAbsPath)) { /* special playlists like history etc. can't have an association */ specialPlaylist = true; diff --git a/ui/drivers/qt/playlistthumbnaildownload.cpp b/ui/drivers/qt/playlistthumbnaildownload.cpp index 985e7bb283..cf30883755 100644 --- a/ui/drivers/qt/playlistthumbnaildownload.cpp +++ b/ui/drivers/qt/playlistthumbnaildownload.cpp @@ -50,6 +50,8 @@ void MainWindow::onPlaylistThumbnailDownloadNetworkSslErrors(const QListcancel(); + m_playlistThumbnailDownloadWasCanceled = true; + RARCH_LOG("[Qt]: Playlist thumbnail download was canceled.\n"); } void MainWindow::onPlaylistThumbnailDownloadFinished() @@ -147,7 +149,7 @@ void MainWindow::onPlaylistThumbnailDownloadFinished() emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": Code " + QString::number(code) + ": " + errorData);*/ } - if (m_pendingPlaylistThumbnails.count() > 0) + if (!m_playlistThumbnailDownloadWasCanceled && m_pendingPlaylistThumbnails.count() > 0) { QHash nextThumbnail = m_pendingPlaylistThumbnails.takeAt(0); ViewType viewType = getCurrentViewType(); @@ -250,9 +252,7 @@ void MainWindow::downloadNextPlaylistThumbnail(QString system, QString title, QS /* make sure any previous connection is removed first */ disconnect(m_playlistThumbnailDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); - disconnect(m_playlistThumbnailDownloadProgressDialog, SIGNAL(canceled()), m_playlistThumbnailDownloadProgressDialog, SLOT(cancel())); connect(m_playlistThumbnailDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); - connect(m_playlistThumbnailDownloadProgressDialog, SIGNAL(canceled()), m_playlistThumbnailDownloadProgressDialog, SLOT(cancel())); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onPlaylistThumbnailDownloadNetworkError(QNetworkReply::NetworkError))); connect(reply, SIGNAL(sslErrors(const QList&)), this, SLOT(onPlaylistThumbnailDownloadNetworkSslErrors(const QList&))); @@ -287,6 +287,7 @@ void MainWindow::downloadPlaylistThumbnails(QString playlistPath) m_pendingPlaylistThumbnails.clear(); m_downloadedThumbnails = 0; m_failedThumbnails = 0; + m_playlistThumbnailDownloadWasCanceled = false; if (playlistItems.count() == 0) return; diff --git a/ui/drivers/qt/thumbnaildownload.cpp b/ui/drivers/qt/thumbnaildownload.cpp index f70ffcd13a..8dd7cc8c6b 100644 --- a/ui/drivers/qt/thumbnaildownload.cpp +++ b/ui/drivers/qt/thumbnaildownload.cpp @@ -285,9 +285,7 @@ void MainWindow::downloadThumbnail(QString system, QString title, QUrl url) /* make sure any previous connection is removed first */ disconnect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); - disconnect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailDownloadProgressDialog, SLOT(cancel())); connect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); - connect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailDownloadProgressDialog, SLOT(cancel())); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onThumbnailDownloadNetworkError(QNetworkReply::NetworkError))); connect(reply, SIGNAL(sslErrors(const QList&)), this, SLOT(onThumbnailDownloadNetworkSslErrors(const QList&))); diff --git a/ui/drivers/qt/thumbnailpackdownload.cpp b/ui/drivers/qt/thumbnailpackdownload.cpp index 8fad5548f9..a9b551498b 100644 --- a/ui/drivers/qt/thumbnailpackdownload.cpp +++ b/ui/drivers/qt/thumbnailpackdownload.cpp @@ -284,9 +284,7 @@ void MainWindow::downloadAllThumbnails(QString system, QUrl url) /* make sure any previous connection is removed first */ disconnect(m_thumbnailPackDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); - disconnect(m_thumbnailPackDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailPackDownloadProgressDialog, SLOT(cancel())); connect(m_thumbnailPackDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); - connect(m_thumbnailPackDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailPackDownloadProgressDialog, SLOT(cancel())); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onThumbnailPackDownloadNetworkError(QNetworkReply::NetworkError))); connect(reply, SIGNAL(sslErrors(const QList&)), this, SLOT(onThumbnailPackDownloadNetworkSslErrors(const QList&))); diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index b0bbc26cce..223df5ffcc 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -333,6 +333,7 @@ MainWindow::MainWindow(QWidget *parent) : ,m_pendingPlaylistThumbnails() ,m_downloadedThumbnails(0) ,m_failedThumbnails(0) + ,m_playlistThumbnailDownloadWasCanceled(false) { settings_t *settings = config_get_ptr(); QDir playlistDir(settings->paths.directory_playlist); @@ -555,6 +556,15 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_gridLayoutWidget, SIGNAL(filesDropped(QStringList)), this, SLOT(onPlaylistFilesDropped(QStringList))); connect(m_gridLayoutWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onFileDropWidgetContextMenuRequested(const QPoint&))); + connect(m_playlistThumbnailDownloadProgressDialog, SIGNAL(canceled()), m_playlistThumbnailDownloadProgressDialog, SLOT(cancel())); + connect(m_playlistThumbnailDownloadProgressDialog, SIGNAL(canceled()), this, SLOT(onPlaylistThumbnailDownloadCanceled())); + + connect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailDownloadProgressDialog, SLOT(cancel())); + connect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), this, SLOT(onThumbnailDownloadCanceled())); + + connect(m_thumbnailPackDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailPackDownloadProgressDialog, SLOT(cancel())); + connect(m_thumbnailPackDownloadProgressDialog, SIGNAL(canceled()), this, SLOT(onThumbnailPackDownloadCanceled())); + connect(this, SIGNAL(itemChanged()), this, SLOT(onItemChanged())); connect(this, SIGNAL(gridItemChanged(QString)), this, SLOT(onGridItemChanged(QString))); connect(this, SIGNAL(gotThumbnailDownload(QString,QString)), this, SLOT(onDownloadThumbnail(QString,QString))); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index fd9375ffe6..9baf33547d 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -506,6 +506,7 @@ private: QVector > m_pendingPlaylistThumbnails; unsigned m_downloadedThumbnails; unsigned m_failedThumbnails; + bool m_playlistThumbnailDownloadWasCanceled; protected: void closeEvent(QCloseEvent *event); From 3010ef8775698d39ad0b8a17a57b3b572aa6eef3 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Tue, 28 Aug 2018 11:34:08 -0400 Subject: [PATCH 164/182] Qt: do not create a new playlist if a name was not specified --- ui/drivers/qt/playlist.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp index ce2d1c5eb7..25f8abc53a 100644 --- a/ui/drivers/qt/playlist.cpp +++ b/ui/drivers/qt/playlist.cpp @@ -596,10 +596,13 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) QString newPlaylistPath = playlistDirAbsPath + "/" + name + file_path_str(FILE_PATH_LPL_EXTENSION); QFile file(newPlaylistPath); - if (file.open(QIODevice::WriteOnly)) - file.close(); + if (!name.isEmpty()) + { + if (file.open(QIODevice::WriteOnly)) + file.close(); - reloadPlaylists(); + reloadPlaylists(); + } } else if (selectedItem && selectedAction == hideAction.data()) { From 613ff650d0aea9746ad97b495c7cff149cff1131 Mon Sep 17 00:00:00 2001 From: Joselagem <31918687+Joselagem@users.noreply.github.com> Date: Sun, 8 Jul 2018 06:59:45 +0200 Subject: [PATCH 165/182] Update languages files US and ES MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update languages files US and ES Actualización de los archivos de idioma US y ES --- intl/msg_hash_es.h | 40 +++++++++++++++++++++++++++++++++ intl/msg_hash_us.h | 56 +++++++++++++++++++++++++++++++++------------- 2 files changed, 80 insertions(+), 16 deletions(-) diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 14103c2515..1af2e08e4f 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -7382,3 +7382,43 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, "Restablecer parámetro" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, + "Descargar miniatura" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, + "Ya hay un descarga en progreso" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, + "Empezar en esta Playlist:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, + "Descargar todas las miniaturas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_ENTIRE_SYSTEM, + "Sistema completo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_THIS_PLAYLIST, + "Esta Playlist" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, + "Miniaturas descargadas correctamente" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_PLAYLIST_THUMBNAIL_PROGRESS, + "Exitos: %1 Fallos: %2" + ) +MSG_HASH( + MSG_DEVICE_CONFIGURED_IN_PORT, + "Configurado en puerto:" + ) +MSG_HASH( + MSG_FAILED_TO_SET_DISK, + "Fallo al establecer disco" + ) \ No newline at end of file diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 38f6bade70..0f39b633c3 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -7386,19 +7386,43 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, "Reset Parameter" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, - "Download thumbnail") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, - "A download is already in progress.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, - "Start on playlist:") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, - "Download All Thumbnails") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_ENTIRE_SYSTEM, - "Entire System") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_THIS_PLAYLIST, - "This Playlist") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, - "Thumbnails downloaded successfully.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_PLAYLIST_THUMBNAIL_PROGRESS, - "Succeeded: %1 Failed: %2") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, + "Download thumbnail" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, + "A download is already in progress." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, + "Start on playlist:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, + "Download All Thumbnails" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_ENTIRE_SYSTEM, + "Entire System" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_THIS_PLAYLIST, + "This Playlist" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, + "Thumbnails downloaded successfully." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_PLAYLIST_THUMBNAIL_PROGRESS, + "Succeeded: %1 Failed: %2" + ) +MSG_HASH( + MSG_DEVICE_CONFIGURED_IN_PORT, + "Configured in port:" + ) +MSG_HASH( + MSG_FAILED_TO_SET_DISK, + "Failed to set disk" + ) \ No newline at end of file From 2d9f00f358bc17cc7fd524421a61605ae3c4781e Mon Sep 17 00:00:00 2001 From: Alfrix Date: Tue, 28 Aug 2018 16:37:48 -0300 Subject: [PATCH 166/182] Bind sublabel cheat apply after load --- menu/cbs/menu_cbs_sublabel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 25ef29af8a..2c292437f0 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -1949,6 +1949,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_show_wimp); break; #endif + case MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_LOAD: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cheat_apply_after_load); + break; default: case MSG_UNKNOWN: return -1; From 72345446693c8997fa7de7fe7eabf75f92ad26cb Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 29 Aug 2018 01:48:37 +0200 Subject: [PATCH 167/182] Update version --- pkg/android/phoenix/AndroidManifest.xml | 4 ++-- pkg/android/phoenix64/AndroidManifest.xml | 4 ++-- pkg/apple/OSX/Info.plist | 4 ++-- pkg/apple/RetroArch_iOS9-Info.plist | 2 +- pkg/apple/iOS/Info.plist | 4 ++-- pkg/sailfishos/retroarch-sailfishos.spec | 2 +- version.all | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/android/phoenix/AndroidManifest.xml b/pkg/android/phoenix/AndroidManifest.xml index 703a158568..7e5c77ceeb 100644 --- a/pkg/android/phoenix/AndroidManifest.xml +++ b/pkg/android/phoenix/AndroidManifest.xml @@ -1,8 +1,8 @@ diff --git a/pkg/android/phoenix64/AndroidManifest.xml b/pkg/android/phoenix64/AndroidManifest.xml index bbcfe2d309..56e834cf01 100644 --- a/pkg/android/phoenix64/AndroidManifest.xml +++ b/pkg/android/phoenix64/AndroidManifest.xml @@ -1,8 +1,8 @@ diff --git a/pkg/apple/OSX/Info.plist b/pkg/apple/OSX/Info.plist index aeee252500..a28050a571 100644 --- a/pkg/apple/OSX/Info.plist +++ b/pkg/apple/OSX/Info.plist @@ -30,11 +30,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.7.3 + 1.7.4 CFBundleSignature ???? CFBundleVersion - 1.7.2 + 1.7.4 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHighResolutionCapable diff --git a/pkg/apple/RetroArch_iOS9-Info.plist b/pkg/apple/RetroArch_iOS9-Info.plist index 42f8a9f2f8..ffc3cefb41 100644 --- a/pkg/apple/RetroArch_iOS9-Info.plist +++ b/pkg/apple/RetroArch_iOS9-Info.plist @@ -37,7 +37,7 @@ CFBundleSignature ???? CFBundleVersion - 1.7.2 + 1.7.4 LSRequiresIPhoneOS UIApplicationExitsOnSuspend diff --git a/pkg/apple/iOS/Info.plist b/pkg/apple/iOS/Info.plist index 8afa2ae3ad..02f641bde5 100644 --- a/pkg/apple/iOS/Info.plist +++ b/pkg/apple/iOS/Info.plist @@ -33,11 +33,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.7.2 + 1.7.4 CFBundleSignature ???? CFBundleVersion - 1.7.2 + 1.7.4 LSRequiresIPhoneOS LSSupportsOpeningDocumentsInPlace diff --git a/pkg/sailfishos/retroarch-sailfishos.spec b/pkg/sailfishos/retroarch-sailfishos.spec index e5e54448b2..6d2d5558b3 100644 --- a/pkg/sailfishos/retroarch-sailfishos.spec +++ b/pkg/sailfishos/retroarch-sailfishos.spec @@ -1,5 +1,5 @@ Name: retroarch -Version: 1.7.3 +Version: 1.7.4 Release: v1.2 Summary: Official reference frontend for libretro diff --git a/version.all b/version.all index bb6f3b2629..6683f2e43c 100644 --- a/version.all +++ b/version.all @@ -6,8 +6,8 @@ # /* - pkg/snap/snapcraft.yaml (including the github url) */ #if 0 -RARCH_VERSION="1.7.3" +RARCH_VERSION="1.7.4" #endif #ifndef PACKAGE_VERSION -#define PACKAGE_VERSION "1.7.3" +#define PACKAGE_VERSION "1.7.4" #endif From c746115bbd0600b119c8fc90ba66f1a2e7063b57 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 29 Aug 2018 00:25:19 -0400 Subject: [PATCH 168/182] Qt: keep trying to download remaining thumbnails if any fail to open for writing (probably just illegal characters in filename) --- ui/drivers/qt/playlistthumbnaildownload.cpp | 13 +++++++++++-- ui/drivers/qt/thumbnaildownload.cpp | 13 +++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/ui/drivers/qt/playlistthumbnaildownload.cpp b/ui/drivers/qt/playlistthumbnaildownload.cpp index cf30883755..e7348c0eae 100644 --- a/ui/drivers/qt/playlistthumbnaildownload.cpp +++ b/ui/drivers/qt/playlistthumbnaildownload.cpp @@ -231,9 +231,18 @@ void MainWindow::downloadNextPlaylistThumbnail(QString system, QString title, QS if (!m_playlistThumbnailDownloadFile.open(QIODevice::WriteOnly)) { - m_playlistThumbnailDownloadProgressDialog->cancel(); - showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + m_failedThumbnails++; + RARCH_ERR("[Qt]: Could not open file for writing: %s\n", fileNameData); + + if (m_pendingPlaylistThumbnails.count() > 0) + { + QHash nextThumbnail = m_pendingPlaylistThumbnails.takeAt(0); + downloadNextPlaylistThumbnail(nextThumbnail.value("db_name"), nextThumbnail.value("label_noext"), nextThumbnail.value("type")); + } + else + m_playlistThumbnailDownloadProgressDialog->cancel(); + return; } } diff --git a/ui/drivers/qt/thumbnaildownload.cpp b/ui/drivers/qt/thumbnaildownload.cpp index 8dd7cc8c6b..c5e5282ea5 100644 --- a/ui/drivers/qt/thumbnaildownload.cpp +++ b/ui/drivers/qt/thumbnaildownload.cpp @@ -257,6 +257,19 @@ void MainWindow::downloadThumbnail(QString system, QString title, QUrl url) m_thumbnailDownloadProgressDialog->cancel(); showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); RARCH_ERR("[Qt]: Could not open file for writing: %s\n", fileNameData); + + if (m_thumbnailDownloadReply) + { + m_thumbnailDownloadReply->disconnect(); + m_thumbnailDownloadReply->abort(); + m_thumbnailDownloadReply->deleteLater(); + } + + if (m_pendingThumbnailDownloadTypes.isEmpty()) + m_thumbnailDownloadProgressDialog->cancel(); + else + downloadThumbnail(system, title); + return; } } From 95ad8798eef4c605e1541fb9000fc8079e41c7e3 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 29 Aug 2018 00:42:34 -0400 Subject: [PATCH 169/182] Qt: scrub thumbnail titles according to No-Intro before downloading, fixes #7149 --- ui/drivers/qt/playlistthumbnaildownload.cpp | 1 + ui/drivers/qt/thumbnaildownload.cpp | 1 + ui/drivers/qt/ui_qt_window.cpp | 12 ++++++++++++ ui/drivers/ui_qt.h | 1 + 4 files changed, 15 insertions(+) diff --git a/ui/drivers/qt/playlistthumbnaildownload.cpp b/ui/drivers/qt/playlistthumbnaildownload.cpp index e7348c0eae..52e4b86677 100644 --- a/ui/drivers/qt/playlistthumbnaildownload.cpp +++ b/ui/drivers/qt/playlistthumbnaildownload.cpp @@ -201,6 +201,7 @@ void MainWindow::downloadNextPlaylistThumbnail(QString system, QString title, QS if (!settings) return; + title = getScrubbedString(title); systemUnderscore = systemUnderscore.replace(" ", "_"); urlString = QString(THUMBNAIL_URL_HEADER) + systemUnderscore + THUMBNAIL_URL_BRANCH + type + "/" + title + THUMBNAIL_URL_FOOTER; diff --git a/ui/drivers/qt/thumbnaildownload.cpp b/ui/drivers/qt/thumbnaildownload.cpp index c5e5282ea5..c54d9b85aa 100644 --- a/ui/drivers/qt/thumbnaildownload.cpp +++ b/ui/drivers/qt/thumbnaildownload.cpp @@ -221,6 +221,7 @@ void MainWindow::downloadThumbnail(QString system, QString title, QUrl url) if (!settings || m_pendingThumbnailDownloadTypes.isEmpty()) return; + title = getScrubbedString(title); downloadType = m_pendingThumbnailDownloadTypes.takeFirst(); systemUnderscore = systemUnderscore.replace(" ", "_"); diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 223df5ffcc..1699c9a36c 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -3152,6 +3152,18 @@ int MainWindow::onExtractArchive(QString path, QString extractionDir, QString te return returnerr; } +QString MainWindow::getScrubbedString(QString str) +{ + const QLatin1Literal chars("&*/:`\"<>?\\|"); + + foreach (QChar ch, chars) + { + str.replace(ch, "_"); + } + + return str; +} + static void* ui_window_qt_init(void) { ui_window.qtWindow = new MainWindow(); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 9baf33547d..323c25b039 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -287,6 +287,7 @@ public: static double lerp(double x, double y, double a, double b, double d); QString getSpecialPlaylistPath(SpecialPlaylist playlist); QVector > getPlaylists(); + QString getScrubbedString(QString str); signals: void thumbnailChanged(const QPixmap &pixmap); From 56c9a37e5a45705e8bfb47cf95a7416bb6082918 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 29 Aug 2018 11:34:36 -0400 Subject: [PATCH 170/182] Qt: initial core options dialog --- Makefile.common | 2 + griffin/griffin_cpp.cpp | 1 + intl/msg_hash_ja.h | 2 + intl/msg_hash_us.h | 6 +- menu/cbs/menu_cbs_ok.c | 4 +- msg_hash.h | 1 + ui/drivers/qt/coreoptionsdialog.cpp | 308 ++++++++++++++++++++++++++++ ui/drivers/qt/coreoptionsdialog.h | 39 ++++ ui/drivers/qt/ui_qt_window.cpp | 19 ++ ui/drivers/ui_qt.cpp | 1 + ui/drivers/ui_qt.h | 5 + 11 files changed, 385 insertions(+), 3 deletions(-) create mode 100644 ui/drivers/qt/coreoptionsdialog.cpp create mode 100644 ui/drivers/qt/coreoptionsdialog.h diff --git a/Makefile.common b/Makefile.common index d32bea96df..125afe8532 100644 --- a/Makefile.common +++ b/Makefile.common @@ -346,6 +346,7 @@ OBJ += ui/drivers/ui_qt.o \ ui/drivers/qt/ui_qt_msg_window.o \ ui/drivers/qt/flowlayout.o \ ui/drivers/qt/shaderparamsdialog.o \ + ui/drivers/qt/coreoptionsdialog.o \ ui/drivers/qt/filedropwidget.o \ ui/drivers/qt/coreinfodialog.o \ ui/drivers/qt/playlistentrydialog.o \ @@ -360,6 +361,7 @@ MOC_HEADERS += ui/drivers/ui_qt.h \ ui/drivers/qt/ui_qt_load_core_window.h \ ui/drivers/qt/flowlayout.h \ ui/drivers/qt/shaderparamsdialog.h \ + ui/drivers/qt/coreoptionsdialog.h \ ui/drivers/qt/filedropwidget.h \ ui/drivers/qt/coreinfodialog.h \ ui/drivers/qt/playlistentrydialog.h \ diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index 56f15070f7..c3b2bc7116 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -43,6 +43,7 @@ UI #include "../ui/drivers/qt/ui_qt_application.cpp" #include "../ui/drivers/qt/flowlayout.cpp" #include "../ui/drivers/qt/shaderparamsdialog.cpp" +#include "../ui/drivers/qt/coreoptionsdialog.cpp" #include "../ui/drivers/qt/filedropwidget.cpp" #include "../ui/drivers/qt/coreinfodialog.cpp" #include "../ui/drivers/qt/playlistentrydialog.cpp" diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index ed2daaa004..b58764d5ea 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3804,3 +3804,5 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, "サムネイルのダウンロードが成功しました。") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_PLAYLIST_THUMBNAIL_PROGRESS, "成功した数: %1 失敗した数: %2") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CORE_OPTIONS, + "コア設定") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 0f39b633c3..67eb6e7518 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -7425,4 +7425,8 @@ MSG_HASH( MSG_HASH( MSG_FAILED_TO_SET_DISK, "Failed to set disk" - ) \ No newline at end of file + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CORE_OPTIONS, + "Core Options" + ) diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 6135befeed..69991840ff 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -847,7 +847,7 @@ int generic_action_ok_displaylist_push(const char *path, setting->max = (int) pow(2,pow((double) 2,cheat_manager_state.working_cheat.memory_search_size))-1; setting = menu_setting_find(msg_hash_to_str(MENU_ENUM_LABEL_CHEAT_ADDRESS_BIT_POSITION)); if ( setting ) - { + { int max_bit_position = cheat_manager_state.working_cheat.memory_search_size<3 ? 7 : 0 ; setting->max = max_bit_position ; } @@ -3498,7 +3498,7 @@ static int action_ok_option_create(const char *path, return false; } - if(config_file_write(conf, game_path)) + if (config_file_write(conf, game_path)) { runloop_msg_queue_push( msg_hash_to_str(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY), diff --git a/msg_hash.h b/msg_hash.h index 10661c8675..c68223c761 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -2012,6 +2012,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_THIS_PLAYLIST, MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_PLAYLIST_THUMBNAIL_PROGRESS, + MENU_ENUM_LABEL_VALUE_QT_CORE_OPTIONS, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/coreoptionsdialog.cpp b/ui/drivers/qt/coreoptionsdialog.cpp new file mode 100644 index 0000000000..088b3e7aef --- /dev/null +++ b/ui/drivers/qt/coreoptionsdialog.cpp @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coreoptionsdialog.h" +#include "../ui_qt.h" + +extern "C" { +#include +#include +#include +#include "../../../command.h" +#include "../../../configuration.h" +#include "../../../retroarch.h" +#include "../../../paths.h" +#include "../../../file_path_special.h" +#include "../../../managers/core_option_manager.h" +} + +CoreOptionsDialog::CoreOptionsDialog(QWidget *parent) : + QDialog(parent) + ,m_layout() + ,m_scrollArea() +{ + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CORE_OPTIONS)); + setObjectName("coreOptionsDialog"); + + resize(720, 480); + + QTimer::singleShot(0, this, SLOT(clearLayout())); +} + +CoreOptionsDialog::~CoreOptionsDialog() +{ +} + +void CoreOptionsDialog::resizeEvent(QResizeEvent *event) +{ + QDialog::resizeEvent(event); + + if (!m_scrollArea) + return; + + m_scrollArea->resize(event->size()); + + emit resized(event->size()); +} + +void CoreOptionsDialog::closeEvent(QCloseEvent *event) +{ + QDialog::closeEvent(event); + + emit closed(); +} + +void CoreOptionsDialog::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QDialog::paintEvent(event); +} + +void CoreOptionsDialog::clearLayout() +{ + QWidget *widget = NULL; + + if (m_scrollArea) + { + foreach (QObject *obj, children()) + { + obj->deleteLater(); + } + } + + m_layout = new QVBoxLayout(); + + widget = new QWidget(); + widget->setLayout(m_layout); + widget->setObjectName("coreOptionsWidget"); + + m_scrollArea = new QScrollArea(); + + m_scrollArea->setParent(this); + m_scrollArea->setWidgetResizable(true); + m_scrollArea->setWidget(widget); + m_scrollArea->setObjectName("coreOptionsScrollArea"); + m_scrollArea->show(); +} + +void CoreOptionsDialog::reload() +{ + buildLayout(); +} + +void CoreOptionsDialog::onSaveGameSpecificOptions() +{ + char game_path[PATH_MAX_LENGTH]; + config_file_t *conf = NULL; + + game_path[0] = '\0'; + + if (!retroarch_validate_game_options(game_path, sizeof(game_path), true)) + { + QMessageBox::critical(this, msg_hash_to_str(MSG_ERROR), msg_hash_to_str(MSG_ERROR_SAVING_CORE_OPTIONS_FILE)); + return; + } + + conf = config_file_new(game_path); + + if (!conf) + { + conf = config_file_new(NULL); + + if (!conf) + { + QMessageBox::critical(this, msg_hash_to_str(MSG_ERROR), msg_hash_to_str(MSG_ERROR_SAVING_CORE_OPTIONS_FILE)); + return; + } + } + + if (config_file_write(conf, game_path)) + { + runloop_msg_queue_push( + msg_hash_to_str(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY), + 1, 100, true); + path_set(RARCH_PATH_CORE_OPTIONS, game_path); + } + + config_file_free(conf); +} + +void CoreOptionsDialog::onCoreOptionComboBoxCurrentIndexChanged(int index) +{ + QComboBox *comboBox = qobject_cast(sender()); + QString key, val; + size_t opts = 0; + unsigned i, k; + + if (!comboBox) + return; + + key = comboBox->itemData(index, Qt::UserRole).toString(); + val = comboBox->itemText(index); + + if (rarch_ctl(RARCH_CTL_HAS_CORE_OPTIONS, NULL)) + { + rarch_ctl(RARCH_CTL_GET_CORE_OPTION_SIZE, &opts); + + if (opts) + { + core_option_manager_t *coreopts = NULL; + + rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts); + + if (coreopts) + { + for (i = 0; i < opts; i++) + { + QString optKey; + struct core_option *option = static_cast(&coreopts->opts[i]); + + if (!option) + continue; + + optKey = option->key; + + if (key == optKey) + { + for (k = 0; k < option->vals->size; k++) + { + QString str = option->vals->elems[k].data; + + if (!str.isEmpty() && str == val) + core_option_manager_set_val(coreopts, i, k); + } + } + } + } + } + } +} + +void CoreOptionsDialog::buildLayout() +{ + QFormLayout *form = NULL; + settings_t *settings = config_get_ptr(); + size_t opts = 0; + int i; + unsigned j, k; + + clearLayout(); + + if (rarch_ctl(RARCH_CTL_HAS_CORE_OPTIONS, NULL)) + { + rarch_ctl(RARCH_CTL_GET_CORE_OPTION_SIZE, &opts); + + if (opts) + { + core_option_manager_t *coreopts = NULL; + + form = new QFormLayout(); + + if (settings->bools.game_specific_options) + { + rarch_system_info_t *system = runloop_get_system_info(); + QString contentLabel; + QString label; + + if (system) + contentLabel = QFileInfo(path_get(RARCH_PATH_BASENAME)).completeBaseName(); + + if (!contentLabel.isEmpty()) + { + if (!rarch_ctl(RARCH_CTL_IS_GAME_OPTIONS_ACTIVE, NULL)) + label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE); + else + label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE); + + if (!label.isEmpty()) + { + QHBoxLayout *gameOptionsLayout = new QHBoxLayout(); + QPushButton *button = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SAVE), this); + + connect(button, SIGNAL(clicked()), this, SLOT(onSaveGameSpecificOptions())); + + gameOptionsLayout->addWidget(new QLabel(contentLabel, this)); + gameOptionsLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Preferred)); + gameOptionsLayout->addWidget(button); + + form->addRow(label, gameOptionsLayout); + } + } + } + + rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts); + + if (coreopts) + { + for (j = 0; j < opts; j++) + { + QString desc = core_option_manager_get_desc(coreopts, j); + QString val = core_option_manager_get_val(coreopts, j); + QComboBox *comboBox = NULL; + struct core_option *option = NULL; + + if (desc.isEmpty() || !coreopts->opts) + continue; + + option = static_cast(&coreopts->opts[j]); + + if (!option->vals || option->vals->size == 0) + continue; + + comboBox = new QComboBox(this); + + for (k = 0; k < option->vals->size; k++) + { + comboBox->addItem(option->vals->elems[k].data, option->key); + } + + comboBox->setCurrentText(val); + + /* Only connect the signal after setting the default item */ + connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onCoreOptionComboBoxCurrentIndexChanged(int))); + + form->addRow(desc, comboBox); + } + + m_layout->addLayout(form); + } + } + } + + if (!opts) + { + QLabel *noParamsLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE), this); + noParamsLabel->setAlignment(Qt::AlignCenter); + + m_layout->addWidget(noParamsLabel); + } + + m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); + + resize(width() + 1, height()); + show(); + resize(width() - 1, height()); +} diff --git a/ui/drivers/qt/coreoptionsdialog.h b/ui/drivers/qt/coreoptionsdialog.h new file mode 100644 index 0000000000..2a9c29023e --- /dev/null +++ b/ui/drivers/qt/coreoptionsdialog.h @@ -0,0 +1,39 @@ +#ifndef COREOPTIONSDIALOG_H +#define COREOPTIONSDIALOG_H + +#include +#include + +class QCloseEvent; +class QResizeEvent; +class QVBoxLayout; +class QFormLayout; +class QLayout; +class QScrollArea; + +class CoreOptionsDialog : public QDialog +{ + Q_OBJECT +public: + CoreOptionsDialog(QWidget *parent = 0); + ~CoreOptionsDialog(); +signals: + void closed(); + void resized(QSize size); +public slots: + void reload(); +private slots: + void clearLayout(); + void buildLayout(); + void onSaveGameSpecificOptions(); + void onCoreOptionComboBoxCurrentIndexChanged(int index); +private: + QPointer m_layout; + QPointer m_scrollArea; +protected: + void closeEvent(QCloseEvent *event); + void resizeEvent(QResizeEvent *event); + void paintEvent(QPaintEvent *event); +}; + +#endif diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 1699c9a36c..f882057ddb 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -45,6 +45,7 @@ #include "ui_qt_themes.h" #include "flowlayout.h" #include "shaderparamsdialog.h" +#include "coreoptionsdialog.h" #include "filedropwidget.h" #include "coreinfodialog.h" #include "playlistentrydialog.h" @@ -316,6 +317,7 @@ MainWindow::MainWindow(QWidget *parent) : ,m_playlistEntryDialog(NULL) ,m_statusMessageElapsedTimer() ,m_shaderParamsDialog(new ShaderParamsDialog()) + ,m_coreOptionsDialog(new CoreOptionsDialog()) ,m_networkManager(new QNetworkAccessManager(this)) ,m_updateProgressDialog(new QProgressDialog()) ,m_updateFile() @@ -574,6 +576,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(this, SIGNAL(gotStatusMessage(QString,unsigned,unsigned,bool)), this, SLOT(onGotStatusMessage(QString,unsigned,unsigned,bool)), Qt::AutoConnection); connect(this, SIGNAL(gotReloadPlaylists()), this, SLOT(onGotReloadPlaylists()), Qt::AutoConnection); connect(this, SIGNAL(gotReloadShaderParams()), this, SLOT(onGotReloadShaderParams()), Qt::AutoConnection); + connect(this, SIGNAL(gotReloadCoreOptions()), this, SLOT(onGotReloadCoreOptions()), Qt::AutoConnection); /* these are always queued */ connect(this, SIGNAL(showErrorMessageDeferred(QString)), this, SLOT(onShowErrorMessage(QString)), Qt::QueuedConnection); @@ -1055,12 +1058,28 @@ void MainWindow::onShaderParamsClicked() onGotReloadShaderParams(); } +void MainWindow::onCoreOptionsClicked() +{ + if (!m_coreOptionsDialog) + return; + + m_coreOptionsDialog->show(); + + onGotReloadCoreOptions(); +} + void MainWindow::onGotReloadShaderParams() { if (m_shaderParamsDialog && m_shaderParamsDialog->isVisible()) m_shaderParamsDialog->reload(); } +void MainWindow::onGotReloadCoreOptions() +{ + if (m_coreOptionsDialog && m_coreOptionsDialog->isVisible()) + m_coreOptionsDialog->reload(); +} + void MainWindow::appendLogMessage(const QString &msg) { emit gotLogMessage(msg); diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index 16d49d632e..1c494f1e99 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -329,6 +329,7 @@ static void* ui_companion_qt_init(void) QObject::connect(viewClosedDocksMenu, SIGNAL(aboutToShow()), mainwindow, SLOT(onViewClosedDocksAboutToShow())); + viewMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CORE_OPTIONS), mainwindow, SLOT(onCoreOptionsClicked())); viewMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS), mainwindow, SLOT(onShaderParamsClicked())); viewMenu->addSeparator(); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 323c25b039..0084890e88 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -86,6 +86,7 @@ class ThumbnailWidget; class ThumbnailLabel; class FlowLayout; class ShaderParamsDialog; +class CoreOptionsDialog; class CoreInfoDialog; class PlaylistEntryDialog; class ViewOptionsDialog; @@ -297,6 +298,7 @@ signals: void gotStatusMessage(QString msg, unsigned priority, unsigned duration, bool flush); void gotReloadPlaylists(); void gotReloadShaderParams(); + void gotReloadCoreOptions(); void showErrorMessageDeferred(QString msg); void showInfoMessageDeferred(QString msg); void extractArchiveDeferred(QString path, QString extractionDir, QString tempExtension, retro_task_callback_t cb); @@ -330,6 +332,7 @@ public slots: void deferReloadPlaylists(); void onGotReloadPlaylists(); void onGotReloadShaderParams(); + void onGotReloadCoreOptions(); void showWelcomeScreen(); void onIconViewClicked(); void onListViewClicked(); @@ -378,6 +381,7 @@ private slots: void onGridItemClicked(ThumbnailWidget *thumbnailWidget = NULL); void onPlaylistFilesDropped(QStringList files); void onShaderParamsClicked(); + void onCoreOptionsClicked(); void onShowErrorMessage(QString msg); void onShowInfoMessage(QString msg); void onContributorsClicked(); @@ -486,6 +490,7 @@ private: PlaylistEntryDialog *m_playlistEntryDialog; QElapsedTimer m_statusMessageElapsedTimer; QPointer m_shaderParamsDialog; + QPointer m_coreOptionsDialog; QNetworkAccessManager *m_networkManager; QProgressDialog *m_updateProgressDialog; From 5a0017a23e5f0400ae6cbb8477c27b194b70f0ec Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 29 Aug 2018 11:42:14 -0400 Subject: [PATCH 171/182] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index cdb99fd1c5..864d7f10db 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,7 @@ - MENU/QT/WIMP: Drag&drop to add new playlist items, add option to add/edit/delete playlists. - MENU/QT/WIMP: Add menu option to update RetroArch (Windows only for now). - MENU/QT/WIMP: Add menu option to manage shaders. +- MENU/QT/WIMP: Add menu option to manage core options. - MENU/XMB: Add new icons for the settings - MENU/XMB: Add an option to show the desktop ui - METAL: Initial work-in-progress video driver for Metal. macOS-only right now, and currently requires macOS 10.13. From 9d43f7f03625c834f8f1d13fa618c1fa0975728e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 29 Aug 2018 21:25:47 +0200 Subject: [PATCH 172/182] Fix French --- intl/msg_hash_es.h | 12 ++++++------ intl/msg_hash_us.h | 2 +- menu/cbs/menu_cbs_ok.c | 6 ------ menu/drivers/xmb.c | 2 -- msg_hash.h | 2 -- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 1af2e08e4f..34ede5266d 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -6481,15 +6481,15 @@ MSG_HASH( "
  • reiniciar RetroArch si actualizaste algo con el \"Actualizador en línea\"
  • \n" "Por último, el contenido debe coincidir las bases de datos existente de aquí. Si aún no funciona, considere enviar un reporte de error." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_SHOW_WIMP, - "Mostrar el menú de escritorio" - ) +#endif MSG_HASH( MENU_ENUM_SUBLABEL_SHOW_WIMP, "Abre el menú de escritorio si fue cerrado" ) -#endif +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + "Mostrar el menú de escritorio" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, "No mostrar esto de nuevo" @@ -7421,4 +7421,4 @@ MSG_HASH( MSG_HASH( MSG_FAILED_TO_SET_DISK, "Fallo al establecer disco" - ) \ No newline at end of file + ) diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 67eb6e7518..2bdf54430b 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -6485,6 +6485,7 @@ MSG_HASH( "
  • restart RetroArch if any of the above was just done
  • \n" "Finally, the content must match existing databases from here. If it is still not working, consider submitting a bug report." ) +#endif MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_WIMP, "Show Desktop Menu" @@ -6493,7 +6494,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SHOW_WIMP, "Opens the desktop menu if closed." ) -#endif MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, "Don't show this again" diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 69991840ff..6bce681d5f 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -88,9 +88,7 @@ enum ACTION_OK_SET_PATH_VIDEO_FILTER, ACTION_OK_SET_PATH_OVERLAY, ACTION_OK_SET_DIRECTORY, -#ifdef HAVE_QT ACTION_OK_SHOW_WIMP, -#endif ACTION_OK_LOAD_CHEAT_FILE_APPEND }; @@ -3531,9 +3529,7 @@ default_action_ok_cmd_func(action_ok_restart_content, CMD_EVENT_RESET) default_action_ok_cmd_func(action_ok_screenshot, CMD_EVENT_TAKE_SCREENSHOT) default_action_ok_cmd_func(action_ok_disk_cycle_tray_status, CMD_EVENT_DISK_EJECT_TOGGLE) default_action_ok_cmd_func(action_ok_shader_apply_changes, CMD_EVENT_SHADERS_APPLY_CHANGES) -#ifdef HAVE_QT default_action_ok_cmd_func(action_ok_show_wimp, CMD_EVENT_UI_COMPANION_TOGGLE) -#endif static int action_ok_reset_core_association(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) @@ -4743,11 +4739,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS: BIND_ACTION_OK(cbs, action_ok_enable_settings); break; -#ifdef HAVE_QT case MENU_ENUM_LABEL_SHOW_WIMP: BIND_ACTION_OK(cbs, action_ok_show_wimp); break; -#endif case MENU_ENUM_LABEL_QUIT_RETROARCH: BIND_ACTION_OK(cbs, action_ok_quit); break; diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 049da29623..c97d052893 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2380,9 +2380,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, return xmb->textures.list[XMB_TEXTURE_RECORD]; case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS: return xmb->textures.list[XMB_TEXTURE_OSD]; -#ifdef HAVE_QT case MENU_ENUM_LABEL_SHOW_WIMP: -#endif case MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS: return xmb->textures.list[XMB_TEXTURE_UI]; case MENU_ENUM_LABEL_POWER_MANAGEMENT_SETTINGS: diff --git a/msg_hash.h b/msg_hash.h index c68223c761..2a76a08cb5 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1505,9 +1505,7 @@ enum msg_hash_enums MENU_LABEL(BUILDBOT_ASSETS_URL), MENU_LABEL(CORE_SET_SUPPORTS_NO_CONTENT_ENABLE), MENU_LABEL(CLOSE_CONTENT), -#ifdef HAVE_QT MENU_LABEL(SHOW_WIMP), -#endif MENU_LABEL(QUIT_RETROARCH), MENU_LABEL(SHUTDOWN), MENU_LABEL(REBOOT), From 2e8361970bf852acedd8d2a6d79f010ddd4c857c Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 29 Aug 2018 18:41:05 -0400 Subject: [PATCH 173/182] Qt: buildfix for older Qt --- ui/drivers/qt/ui_qt_window.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index f882057ddb..1e993bdcb0 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -3173,11 +3173,12 @@ int MainWindow::onExtractArchive(QString path, QString extractionDir, QString te QString MainWindow::getScrubbedString(QString str) { - const QLatin1Literal chars("&*/:`\"<>?\\|"); + const QString chars("&*/:`\"<>?\\|"); + int i; - foreach (QChar ch, chars) + for (i = 0; i < chars.count(); i++) { - str.replace(ch, "_"); + str.replace(chars.at(i), '_'); } return str; From b1643f9275ada6002ac5f90c18faca285e8c896e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 30 Aug 2018 01:46:41 +0200 Subject: [PATCH 174/182] (AArch64) Needs to be set to SDK level 26 for Google Play --- pkg/android/phoenix64/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/android/phoenix64/AndroidManifest.xml b/pkg/android/phoenix64/AndroidManifest.xml index 56e834cf01..eceecb0d32 100644 --- a/pkg/android/phoenix64/AndroidManifest.xml +++ b/pkg/android/phoenix64/AndroidManifest.xml @@ -10,7 +10,7 @@ + android:targetSdkVersion="26" /> From dac40349540070f729d0828782800e8bcc21115a Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 30 Aug 2018 15:56:02 +0200 Subject: [PATCH 175/182] Add PPC ifdefs; kIOHIDUniqueKey is not available on OSX 10.5 --- input/drivers_hid/iohidmanager_hid.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/input/drivers_hid/iohidmanager_hid.c b/input/drivers_hid/iohidmanager_hid.c index 77e9c6defd..2f0a8da0fe 100644 --- a/input/drivers_hid/iohidmanager_hid.c +++ b/input/drivers_hid/iohidmanager_hid.c @@ -56,7 +56,9 @@ struct iohidmanager_hid_adapter apple_input_rec_t *hats; apple_input_rec_t *buttons; uint8_t data[2048]; +#if !(defined(__ppc__) || defined(__ppc64__)) uint32_t uniqueId; +#endif }; CFComparisonResult iohidmanager_sort_elements(const void *val1, const void *val2, void *context) @@ -523,6 +525,7 @@ static uint32_t iohidmanager_hid_device_get_location_id(IOHIDDeviceRef device) CFSTR(kIOHIDLocationIDKey)); } +#if !(defined(__ppc__) || defined(__ppc64__)) static uint32_t iohidmanager_hid_device_get_unique_id(IOHIDDeviceRef device) { /* osx seems to assign an unique id to each device when they are plugged in @@ -530,6 +533,7 @@ static uint32_t iohidmanager_hid_device_get_unique_id(IOHIDDeviceRef device) * other device plugged */ return iohidmanager_hid_device_get_int_property(device,CFSTR(kIOHIDUniqueIDKey)); } +#endif static void iohidmanager_hid_device_get_product_string( IOHIDDeviceRef device, char *buf, size_t len) @@ -561,12 +565,20 @@ static void iohidmanager_hid_device_add_autodetect(unsigned idx, RARCH_LOG("Port %d: %s.\n", idx, device_name); } -static void iohidmanager_hid_device_add_device(IOHIDDeviceRef device, iohidmanager_hid_t* hid) +#if defined(__ppc__) || defined(__ppc64__) +static void iohidmanager_hid_device_add(IOHIDDeviceRef device, + iohidmanager_hid_t* hid) +#else +static void iohidmanager_hid_device_add_device( + IOHIDDeviceRef device, iohidmanager_hid_t* hid) +#endif { int i; /* get device unique id */ +#if !(defined(__ppc__) || defined(__ppc64__)) uint32_t deviceUniqueId = iohidmanager_hid_device_get_unique_id(device); +#endif static const uint32_t axis_use_ids[11] = { @@ -583,6 +595,7 @@ static void iohidmanager_hid_device_add_device(IOHIDDeviceRef device, iohidmanag kHIDUsage_Sim_Brake }; +#if !(defined(__ppc__) || defined(__ppc64__)) /* check if pad was already registered previously (by deterministic method) * if so do not re-add the pad */ for (i=0; iuniqueId == deviceUniqueId) return; } +#endif IOReturn ret; uint16_t dev_vid, dev_pid; @@ -633,7 +647,9 @@ static void iohidmanager_hid_device_add_device(IOHIDDeviceRef device, iohidmanag dev_vid = iohidmanager_hid_device_get_vendor_id (device); dev_pid = iohidmanager_hid_device_get_product_id (device); +#if !(defined(__ppc__) || defined(__ppc64__)) adapter->uniqueId = deviceUniqueId; +#endif adapter->slot = pad_connection_pad_init(hid->slots, adapter->name, dev_vid, dev_pid, adapter, @@ -904,13 +920,14 @@ error: } } - +#if !(defined(__ppc__) || defined(__ppc64__)) static void iohidmanager_hid_device_add(void *data, IOReturn result, void* sender, IOHIDDeviceRef device) { iohidmanager_hid_t *hid = (iohidmanager_hid_t*) hid_driver_get_data(); iohidmanager_hid_device_add_device(device, hid); } +#endif static void iohidmanager_hid_append_matching_dictionary( CFMutableArrayRef array, @@ -1029,7 +1046,11 @@ static int iohidmanager_hid_manager_set_device_matching( hid_list_t * ptr = devList; while (ptr != NULL) { +#if defined(__ppc__) || defined(__ppc64__) + iohidmanager_hid_device_add(ptr->device, hid); +#else iohidmanager_hid_device_add_device(ptr->device, hid); +#endif //printf("%d\n",ptr->lid); ptr = ptr->next; @@ -1039,6 +1060,7 @@ static int iohidmanager_hid_manager_set_device_matching( free(device_array); +#if !(defined(__ppc__) || defined(__ppc64__)) /* register call back to dynamically add device plugged when retroarch is * running * those will be added after the one plugged when retroarch was launched, @@ -1061,6 +1083,7 @@ static int iohidmanager_hid_manager_set_device_matching( iohidmanager_hid_device_add, 0); CFRelease(matcher); +#endif return 0; } From 5af0e582883af20fa1f8e0c454b88e13859ff7d4 Mon Sep 17 00:00:00 2001 From: neville Date: Thu, 30 Aug 2018 16:05:51 +0200 Subject: [PATCH 176/182] - Unset BOM - remove non-latin characters - won't compile on OSX PPC otherwise --- command.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/command.c b/command.c index 9a2f9a6879..40f6310c3e 100644 --- a/command.c +++ b/command.c @@ -1,6 +1,6 @@ -/* RetroArch - A frontend for libretro. +/* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2015-2017 - Andrés Suárez + * Copyright (C) 2015-2017 - Andres Suarez * Copyright (C) 2016-2017 - Brad Parker * * RetroArch is free software: you can redistribute it and/or modify it under the terms From d7899c51aa7ef7b752be97409dafdca8d9597e11 Mon Sep 17 00:00:00 2001 From: neville Date: Thu, 30 Aug 2018 16:18:51 +0200 Subject: [PATCH 177/182] Compatibility fixes for OSX PPC --- frontend/drivers/platform_darwin.m | 4 ++++ gfx/drivers_context/macos_ctx.m | 6 +++++- ui/drivers/ui_cocoa.m | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/frontend/drivers/platform_darwin.m b/frontend/drivers/platform_darwin.m index 4df8be17df..fc026ada7d 100644 --- a/frontend/drivers/platform_darwin.m +++ b/frontend/drivers/platform_darwin.m @@ -286,6 +286,10 @@ static void frontend_darwin_get_name(char *s, size_t len) #endif } +#ifndef MAC_OS_X_VERSION_10_10 +#define MAC_OS_X_VERSION_10_10 101000 +#endif + static void frontend_darwin_get_os(char *s, size_t len, int *major, int *minor) { #if defined(IOS) diff --git a/gfx/drivers_context/macos_ctx.m b/gfx/drivers_context/macos_ctx.m index 7c1aedc2dd..fb518060cf 100644 --- a/gfx/drivers_context/macos_ctx.m +++ b/gfx/drivers_context/macos_ctx.m @@ -404,6 +404,10 @@ static void cocoagl_gfx_ctx_show_mouse(void *data, bool state) #endif } +#ifndef MAC_OS_X_VERSION_10_10 +#define MAC_OS_X_VERSION_10_10 101000 +#endif + static bool cocoagl_gfx_ctx_set_video_mode(void *data, video_frame_info_t *video_info, unsigned width, unsigned height, bool fullscreen) @@ -446,7 +450,7 @@ static bool cocoagl_gfx_ctx_set_video_mode(void *data, } #endif -#if MAC_OS_X_VERSION_10_10 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10 if (g_major == 4 && g_minor == 1) { attributes[6] = NSOpenGLPFAOpenGLProfile; diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index aced897a60..34d8bfc0bf 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -37,7 +37,7 @@ #include "../../retroarch.h" #include "../../tasks/tasks_internal.h" -#if HAVE_METAL +#ifdef HAVE_METAL #import #import #endif From 1222192afb2438880f61b02d35be2c04c5af1a7e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 30 Aug 2018 16:22:02 +0200 Subject: [PATCH 178/182] Add conditionals to maintain backwards compatibility with OSX 10.5 --- ui/drivers/ui_cocoa.m | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index 34d8bfc0bf..ec30ccd531 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -42,6 +42,7 @@ #import #endif +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 @interface WindowListener : NSResponder @end @@ -59,6 +60,7 @@ {} @end +#endif id apple_platform; @@ -72,7 +74,9 @@ id apple_platform; apple_view_type_t _vt; NSView* _renderView; id _sleepActivity; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 WindowListener *_listener; +#endif } @property (nonatomic, retain) NSWindow IBOutlet* window; @@ -264,11 +268,15 @@ static char** waiting_argv; } #endif +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 _listener = [WindowListener new]; +#endif [self.window setAcceptsMouseMovedEvents: YES]; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 [self.window setNextResponder:_listener]; self.window.delegate = _listener; +#endif [[self.window contentView] setAutoresizesSubviews:YES]; @@ -286,8 +294,10 @@ static char** waiting_argv; waiting_argc = 0; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 [self.window makeMainWindow]; [self.window makeKeyWindow]; +#endif [self performSelectorOnMainThread:@selector(rarch_main) withObject:nil waitUntilDone:NO]; } @@ -305,7 +315,9 @@ static char** waiting_argv; _renderView.wantsLayer = NO; _renderView.layer = nil; [_renderView removeFromSuperview]; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 self.window.contentView = nil; +#endif _renderView = nil; } @@ -336,8 +348,13 @@ static char** waiting_argv; _renderView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; _renderView.frame = self.window.contentView.bounds; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 self.window.contentView = _renderView; [self.window.contentView setNextResponder:_listener]; +#else + [self.window.contentView addSubview:_renderView]; + [self.window makeFirstResponder:_renderView]; +#endif } - (apple_view_type_t)viewType { From f35b578c42c6a1cd6b96ec87c4b50a97e0cb9b83 Mon Sep 17 00:00:00 2001 From: neville Date: Thu, 30 Aug 2018 16:29:58 +0200 Subject: [PATCH 179/182] Use constant values instead of MAC_OS_X_VERSION_ - might not be available on earlier OSX versions/xcode --- ui/drivers/cocoa/ui_cocoa_msg_window.m | 2 +- ui/drivers/ui_cocoa.m | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/ui/drivers/cocoa/ui_cocoa_msg_window.m b/ui/drivers/cocoa/ui_cocoa_msg_window.m index faf6739b99..71c83393c6 100644 --- a/ui/drivers/cocoa/ui_cocoa_msg_window.m +++ b/ui/drivers/cocoa/ui_cocoa_msg_window.m @@ -80,7 +80,7 @@ static enum ui_msg_window_response ui_msg_window_cocoa_dialog(ui_msg_window_stat break; } -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 [alert beginSheetModalForWindow:(BRIDGE NSWindow *)ui_companion_driver_get_main_window() completionHandler:^(NSModalResponse returnCode) { [[NSApplication sharedApplication] stopModalWithCode:returnCode]; diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index ec30ccd531..2c4e1fb7b7 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -42,6 +42,10 @@ #import #endif +#ifndef MAC_OS_X_VERSION_10_6 +#define MAC_OS_X_VERSION_10_6 1060 +#endif + #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 @interface WindowListener : NSResponder @end @@ -74,7 +78,7 @@ id apple_platform; apple_view_type_t _vt; NSView* _renderView; id _sleepActivity; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 WindowListener *_listener; #endif } @@ -255,7 +259,7 @@ static char** waiting_argv; { unsigned i; apple_platform = self; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 self.window.collectionBehavior = NSWindowCollectionBehaviorFullScreenPrimary; #else SEL selector = NSSelectorFromString(BOXSTRING("setCollectionBehavior:")); @@ -268,12 +272,12 @@ static char** waiting_argv; } #endif -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 _listener = [WindowListener new]; #endif [self.window setAcceptsMouseMovedEvents: YES]; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 [self.window setNextResponder:_listener]; self.window.delegate = _listener; #endif @@ -294,7 +298,7 @@ static char** waiting_argv; waiting_argc = 0; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 [self.window makeMainWindow]; [self.window makeKeyWindow]; #endif @@ -315,7 +319,7 @@ static char** waiting_argv; _renderView.wantsLayer = NO; _renderView.layer = nil; [_renderView removeFromSuperview]; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 self.window.contentView = nil; #endif _renderView = nil; @@ -348,7 +352,7 @@ static char** waiting_argv; _renderView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; _renderView.frame = self.window.contentView.bounds; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 self.window.contentView = _renderView; [self.window.contentView setNextResponder:_listener]; #else @@ -399,7 +403,7 @@ static char** waiting_argv; - (bool)setDisableDisplaySleep:(bool)disable { -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 if (disable && _sleepActivity == nil) { _sleepActivity = [NSProcessInfo.processInfo beginActivityWithOptions:NSActivityIdleDisplaySleepDisabled reason:@"disable screen saver"]; From ab34a70873637232be341f1c07544d9749e6dddb Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 30 Aug 2018 16:35:44 +0200 Subject: [PATCH 180/182] Start using raw constants for OSX version detection --- frontend/drivers/platform_darwin.m | 6 +----- gfx/drivers_context/cocoa_gl_ctx.m | 2 +- gfx/drivers_context/macos_ctx.m | 8 ++------ libretro-common/include/compat/apple_compat.h | 2 +- ui/drivers/ui_cocoa.m | 6 +----- 5 files changed, 6 insertions(+), 18 deletions(-) diff --git a/frontend/drivers/platform_darwin.m b/frontend/drivers/platform_darwin.m index fc026ada7d..12a9004f93 100644 --- a/frontend/drivers/platform_darwin.m +++ b/frontend/drivers/platform_darwin.m @@ -286,17 +286,13 @@ static void frontend_darwin_get_name(char *s, size_t len) #endif } -#ifndef MAC_OS_X_VERSION_10_10 -#define MAC_OS_X_VERSION_10_10 101000 -#endif - static void frontend_darwin_get_os(char *s, size_t len, int *major, int *minor) { #if defined(IOS) get_ios_version(major, minor); strlcpy(s, "iOS", len); #elif defined(OSX) -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion]; *major = (int)version.majorVersion; *minor = (int)version.minorVersion; diff --git a/gfx/drivers_context/cocoa_gl_ctx.m b/gfx/drivers_context/cocoa_gl_ctx.m index a95478f59d..69911d0cdb 100644 --- a/gfx/drivers_context/cocoa_gl_ctx.m +++ b/gfx/drivers_context/cocoa_gl_ctx.m @@ -365,7 +365,7 @@ static bool cocoagl_gfx_ctx_set_video_mode(void *data, g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 if (g_format == nil) { /* NSOpenGLFPAAllowOfflineRenderers is diff --git a/gfx/drivers_context/macos_ctx.m b/gfx/drivers_context/macos_ctx.m index fb518060cf..64c92a0e76 100644 --- a/gfx/drivers_context/macos_ctx.m +++ b/gfx/drivers_context/macos_ctx.m @@ -404,10 +404,6 @@ static void cocoagl_gfx_ctx_show_mouse(void *data, bool state) #endif } -#ifndef MAC_OS_X_VERSION_10_10 -#define MAC_OS_X_VERSION_10_10 101000 -#endif - static bool cocoagl_gfx_ctx_set_video_mode(void *data, video_frame_info_t *video_info, unsigned width, unsigned height, bool fullscreen) @@ -450,7 +446,7 @@ static bool cocoagl_gfx_ctx_set_video_mode(void *data, } #endif -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 if (g_major == 4 && g_minor == 1) { attributes[6] = NSOpenGLPFAOpenGLProfile; @@ -460,7 +456,7 @@ static bool cocoagl_gfx_ctx_set_video_mode(void *data, g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 if (g_format == nil) { /* NSOpenGLFPAAllowOfflineRenderers is diff --git a/libretro-common/include/compat/apple_compat.h b/libretro-common/include/compat/apple_compat.h index 819b39ecf6..74b6829954 100644 --- a/libretro-common/include/compat/apple_compat.h +++ b/libretro-common/include/compat/apple_compat.h @@ -29,7 +29,7 @@ #ifdef __OBJC__ -#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4) +#if (MAC_OS_X_VERSION_MAX_ALLOWED <= 1040) typedef int NSInteger; typedef unsigned NSUInteger; typedef float CGFloat; diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index 2c4e1fb7b7..c089da2991 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -42,11 +42,7 @@ #import #endif -#ifndef MAC_OS_X_VERSION_10_6 -#define MAC_OS_X_VERSION_10_6 1060 -#endif - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 @interface WindowListener : NSResponder @end From 7f7f23d08ba0494664c1cf941c219d3a84468be2 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 30 Aug 2018 17:38:43 +0200 Subject: [PATCH 181/182] Add conditionals for OSX 10.6 and higher --- ui/drivers/ui_cocoa.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index c089da2991..0d4aec4328 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -370,6 +370,7 @@ static char** waiting_argv; } - (void)setVideoMode:(gfx_ctx_mode_t)mode { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 BOOL isFullScreen = (self.window.styleMask & NSFullScreenWindowMask) == NSFullScreenWindowMask; if (mode.fullscreen && !isFullScreen) { @@ -383,11 +384,14 @@ static char** waiting_argv; } if (mode.width > 0) +#endif { // HACK(sgc): ensure MTKView posts a drawable resize event [self.window setContentSize:NSMakeSize(mode.width-1, mode.height)]; } +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 [self.window setContentSize:NSMakeSize(mode.width, mode.height)]; +#endif } - (void)setCursorVisible:(bool)v { From f16ec700a952e8c8b0f3444bec2aa94b2383fb78 Mon Sep 17 00:00:00 2001 From: neville Date: Thu, 30 Aug 2018 17:45:22 +0200 Subject: [PATCH 182/182] OSX PowerPC - gets it compiling and linking again but doesn't work - left a TODO/FIXME for aussiebloke --- ui/drivers/ui_cocoa.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index 0d4aec4328..76c27bdaf5 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -346,12 +346,14 @@ static char** waiting_argv; } _renderView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - _renderView.frame = self.window.contentView.bounds; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 + _renderView.frame = self.window.contentView.bounds; self.window.contentView = _renderView; [self.window.contentView setNextResponder:_listener]; #else + /* TODO/FIXME - Aussiebloke - we need a workaround for OSX 10.5 for self.window.contentView.bounds - + * error - request for member 'bounds' in something not a structure or union. */ [self.window.contentView addSubview:_renderView]; [self.window makeFirstResponder:_renderView]; #endif

    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

    - * Note that this does not release the currently held - * {@link Camera} instance and must be freed by calling - * {@link #onCameraFree} - */ - public void onCameraStop() - { - if (!camera_service_running) - return; - - if (mCamera != null) - mCamera.stopPreview(); - camera_service_running = false; - } - - /** - * Releases the currently held {@link Camera} instance. - */ - public void onCameraFree() - { - onCameraStop(); - - if (mCamera != null) - mCamera.release(); - } - - /** - * Initializes the camera for use. - */ - public void onCameraInit() - { - if (mCamera != null) - return; - - mCamera = Camera.open(); - } - - /** - * Polls the camera for updates to the {@link SurfaceTexture}. - * - * @return true if polling was successful, false otherwise. - */ - public boolean onCameraPoll() - { - if (!camera_service_running) - return false; - - if (texture == null) - { - Log.i("RetroActivity", "No texture"); - return true; - } - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) - { - if (updateSurface) - { - texture.updateTexImage(); - } - - long newTimestamp = texture.getTimestamp(); - - if (newTimestamp != lastTimestamp) - { - lastTimestamp = newTimestamp; - return true; - } - - return false; - } - - return true; - } - - /** - * Initializes the {@link SurfaceTexture} used by the - * {@link Camera} with a given OpenGL texure ID. - * - * @param gl_texid texture ID to initialize the - * {@link SurfaceTexture} with. - */ - public void onCameraTextureInit(int gl_texid) - { - texture = new SurfaceTexture(gl_texid); - texture.setOnFrameAvailableListener(onCameraFrameAvailableListener); - } - - /** - * Sets the {@link Camera} texture with the texture represented - * by the given OpenGL texture ID. - * - * @param gl_texid The texture ID representing the texture to set the camera to. - * @throws IOException If setting the texture fails. - */ - public void onCameraSetTexture(int gl_texid) throws IOException - { - if (texture == null) - onCameraTextureInit(gl_texid); - - if (mCamera != null) - mCamera.setPreviewTexture(texture); - } - - private final OnFrameAvailableListener onCameraFrameAvailableListener = new OnFrameAvailableListener() - { - @Override - public void onFrameAvailable(SurfaceTexture surfaceTexture) - { - updateSurface = true; - } - }; - - @Override - public void onCreate(Bundle savedInstanceState) - { - // Save the current setting for updates - SharedPreferences prefs = UserPreferences.getPreferences(this); - SharedPreferences.Editor edit = prefs.edit(); - edit.putBoolean("CAMERA_UPDATES_ON", false); - edit.apply(); - - camera_service_running = false; - - super.onCreate(savedInstanceState); - } - - @Override - public void onPause() - { - // Save the current setting for updates - SharedPreferences prefs = UserPreferences.getPreferences(this); - SharedPreferences.Editor edit = prefs.edit(); - edit.putBoolean("CAMERA_UPDATES_ON", camera_service_running); - edit.apply(); - - onCameraStop(); - super.onPause(); - } - - @Override - public void onResume() - { - SharedPreferences prefs = UserPreferences.getPreferences(this); - SharedPreferences.Editor edit = prefs.edit(); - - /* - * Get any previous setting for camera updates - * Gets "false" if an error occurs - */ - if (prefs.contains("CAMERA_UPDATES_ON")) - { - camera_service_running = prefs.getBoolean("CAMERA_UPDATES_ON", false); - if (camera_service_running) - { - onCameraStart(); - } - } - else // Otherwise, turn off camera updates - { - edit.putBoolean("CAMERA_UPDATES_ON", false); - edit.apply(); - camera_service_running = false; - } - super.onResume(); - } - - @Override - public void onDestroy() - { - onCameraFree(); - super.onDestroy(); - } - - @Override - public void onStop() - { - onCameraStop(); - super.onStop(); - } -} diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java deleted file mode 100644 index e660dd2eb9..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.retroarch.browser.retroactivity; - -import com.retroarch.browser.preferences.util.UserPreferences; -import android.annotation.TargetApi; -import android.content.res.Configuration; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.app.UiModeManager; -import android.os.BatteryManager; -import android.os.Build; -import android.os.PowerManager; -import android.util.Log; - -import java.util.concurrent.CountDownLatch; - -/** - * Class which provides common methods for RetroActivity related classes. - */ -public class RetroActivityCommon extends RetroActivityLocation -{ - public static int FRONTEND_POWERSTATE_NONE = 0; - public static int FRONTEND_POWERSTATE_NO_SOURCE = 1; - public static int FRONTEND_POWERSTATE_CHARGING = 2; - public static int FRONTEND_POWERSTATE_CHARGED = 3; - public static int FRONTEND_POWERSTATE_ON_POWER_SOURCE = 4; - public boolean sustainedPerformanceMode = true; - - // Exiting cleanly from NDK seems to be nearly impossible. - // Have to use exit(0) to avoid weird things happening, even with runOnUiThread() approaches. - // Use a separate JNI function to explicitly trigger the readback. - public void onRetroArchExit() - { - finish(); - } - - @TargetApi(24) - public void setSustainedPerformanceMode(boolean on) - { - sustainedPerformanceMode = on; - - if (Build.VERSION.SDK_INT >= 24) { - if (isSustainedPerformanceModeSupported()) { - final CountDownLatch latch = new CountDownLatch(1); - - runOnUiThread(new Runnable() { - @Override - public void run() { - Log.i("RetroActivity", "setting sustained performance mode to " + sustainedPerformanceMode); - - getWindow().setSustainedPerformanceMode(sustainedPerformanceMode); - - latch.countDown(); - } - }); - - try { - latch.await(); - }catch(InterruptedException e) { - e.printStackTrace(); - } - } - } - } - - @TargetApi(24) - public boolean isSustainedPerformanceModeSupported() - { - boolean supported = false; - - if (Build.VERSION.SDK_INT >= 24) - { - PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE); - - if (powerManager.isSustainedPerformanceModeSupported()) - supported = true; - } - - - Log.i("RetroActivity", "isSustainedPerformanceModeSupported? " + supported); - - return supported; - } - - public int getBatteryLevel() - { - IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); - // This doesn't actually register anything (or need to) because we know this particular intent is sticky and we do not specify a BroadcastReceiver anyway - Intent batteryStatus = registerReceiver(null, ifilter); - int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); - int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, 100); - - float percent = ((float)level / (float)scale) * 100.0f; - - Log.i("RetroActivity", "battery: level = " + level + ", scale = " + scale + ", percent = " + percent); - - return (int)percent; - } - - public int getPowerstate() - { - IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); - // This doesn't actually register anything (or need to) because we know this particular intent is sticky and we do not specify a BroadcastReceiver anyway - Intent batteryStatus = registerReceiver(null, ifilter); - int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); - boolean hasBattery = batteryStatus.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false); - boolean isCharging = (status == BatteryManager.BATTERY_STATUS_CHARGING); - boolean isCharged = (status == BatteryManager.BATTERY_STATUS_FULL); - int powerstate = FRONTEND_POWERSTATE_NONE; - - if (isCharged) - powerstate = FRONTEND_POWERSTATE_CHARGED; - else if (isCharging) - powerstate = FRONTEND_POWERSTATE_CHARGING; - else if (!hasBattery) - powerstate = FRONTEND_POWERSTATE_NO_SOURCE; - else - powerstate = FRONTEND_POWERSTATE_ON_POWER_SOURCE; - - Log.i("RetroActivity", "power state = " + powerstate); - - return powerstate; - } - - public boolean isAndroidTV() - { - Configuration config = getResources().getConfiguration(); - UiModeManager uiModeManager = (UiModeManager)getSystemService(UI_MODE_SERVICE); - - if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) - { - Log.i("RetroActivity", "isAndroidTV == true"); - return true; - } - else - { - Log.i("RetroActivity", "isAndroidTV == false"); - return false; - } - } -} diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java deleted file mode 100644 index eba29872a6..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.retroarch.browser.retroactivity; - -import android.view.View; -import android.view.WindowManager; -import android.content.Intent; -import android.content.Context; -import android.hardware.input.InputManager; -import android.os.Build; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public final class RetroActivityFuture extends RetroActivityCamera { - - // If set to true then Retroarch will completely exit when it loses focus - private boolean quitfocus = false; - - @Override - public void onResume() { - super.onResume(); - - setSustainedPerformanceMode(sustainedPerformanceMode); - - if (Build.VERSION.SDK_INT >= 19) { - // Immersive mode - - // Constants from API > 14 - final int API_SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; - final int API_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; - final int API_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; - final int API_SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; - final int API_SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; - - View thisView = getWindow().getDecorView(); - thisView.setSystemUiVisibility(API_SYSTEM_UI_FLAG_LAYOUT_STABLE - | API_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | API_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | API_SYSTEM_UI_FLAG_FULLSCREEN - | API_SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - - // Check for Android UI specific parameters - Intent retro = getIntent(); - String refresh = retro.getStringExtra("REFRESH"); - - // If REFRESH parameter is provided then try to set refreshrate accordingly - if(refresh != null) { - WindowManager.LayoutParams params = getWindow().getAttributes(); - params.preferredRefreshRate = Integer.parseInt(refresh); - getWindow().setAttributes(params); - } - - // If QUITFOCUS parameter is provided then enable that Retroarch quits when focus is lost - quitfocus = retro.hasExtra("QUITFOCUS"); - - // If HIDEMOUSE parameters is provided then hide the mourse cursor - // This requires NVIDIA Android extensions (available on NVIDIA Shield), if they are not - // available then nothing will be done - if (retro.hasExtra("HIDEMOUSE")) hideMouseCursor(); - } - } - - public void hideMouseCursor() { - - // Check for NVIDIA extensions and minimum SDK version - Method mInputManager_setCursorVisibility; - try { mInputManager_setCursorVisibility = - InputManager.class.getMethod("setCursorVisibility", boolean.class); - } - catch (NoSuchMethodException ex) { - return; // Extensions were not available so do nothing - } - - // Hide the mouse cursor - InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE); - try { mInputManager_setCursorVisibility.invoke(inputManager, false); } - catch (InvocationTargetException ite) { } - catch (IllegalAccessException iae) { } - } - - @Override - public void onStop() { - super.onStop(); - - // If QUITFOCUS parameter was set then completely exit Retroarch when focus is lost - if (quitfocus) System.exit(0); - } -} diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java deleted file mode 100644 index 91ccc3f8a6..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.retroarch.browser.retroactivity; - -import com.retroarch.browser.mainmenu.MainMenuActivity; - -import android.content.Intent; -import android.util.Log; - -public class RetroActivityIntent extends RetroActivityCommon { - private Intent pendingIntent = null; - private static final String TAG = "RetroArch"; - - @Override - public void onBackPressed() - { - Log.i("RetroActivity", "onBackKeyPressed"); - Intent retro = new Intent(this, MainMenuActivity.class); - retro.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivity(retro); - } - - @Override - public void onNewIntent(Intent intent) - { - Log.i("RetroActivity", "onNewIntent invoked."); - super.onNewIntent(intent); - setIntent(intent); - pendingIntent = intent; - } - - /** - * Gets the ROM file specified in the pending intent. - * - * @return the ROM file specified in the pending intent. - */ - public String getPendingIntentFullPath() - { - return pendingIntent.getStringExtra("ROM"); - } - - /** - * Gets the specified path to the libretro core in the pending intent. - * - * @return the specified path to the libretro core in the pending intent. - */ - public String getPendingIntentLibretroPath() - { - return pendingIntent.getStringExtra("LIBRETRO"); - } - - /** - * Gets the path specified in the pending intent to the retroarch cfg file. - * - * @return the path specified in the pending intent to the retroarch cfg file. - */ - public String getPendingIntentConfigPath() - { - return pendingIntent.getStringExtra("CONFIGFILE"); - } - - public String getPendingIntentStorageLocation() - { - return pendingIntent.getStringExtra("SDCARD"); - } - - public String getPendingIntentDownloadLocation() - { - return pendingIntent.getStringExtra("DOWNLOADS"); - } - - public String getPendingIntentScreenshotsLocation() - { - return pendingIntent.getStringExtra("SCREENSHOTS"); - } - - /** - * Gets the specified IME in the pending intent. - * - * @return the specified IME in the pending intent. - */ - public String getPendingIntentIME() - { - return pendingIntent.getStringExtra("IME"); - } - - /** - * Checks whether or not a pending intent exists. - * - * @return true if a pending intent exists, false otherwise. - */ - public boolean hasPendingIntent() - { - if (pendingIntent == null) - return false; - - return true; - } - - /** - * Clears the current pending intent. - */ - public void clearPendingIntent() - { - pendingIntent = null; - } -} diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java deleted file mode 100644 index 9fedbf2e7b..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java +++ /dev/null @@ -1,316 +0,0 @@ -package com.retroarch.browser.retroactivity; - -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks; -import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener; -import com.google.android.gms.location.LocationClient; -import com.google.android.gms.location.LocationListener; -import com.google.android.gms.location.LocationRequest; -import com.retroarch.browser.preferences.util.UserPreferences; - -import android.app.NativeActivity; -import android.content.IntentSender; -import android.content.SharedPreferences; -import android.location.Location; -import android.os.Bundle; -import android.util.Log; -import android.widget.Toast; - -/** - * Class that implements location-based functionality for - * the {@link RetroActivityFuture} and {@link RetroActivityPast} - * activities. - */ -public class RetroActivityLocation extends NativeActivity -implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener -{ - /* LOCATION VARIABLES */ - private static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 0; - private LocationClient mLocationClient = null; - private Location mCurrentLocation; - - // Define an object that holds accuracy and frequency parameters - LocationRequest mLocationRequest = null; - boolean mUpdatesRequested = false; - boolean locationChanged = false; - boolean location_service_running = false; - - /** - * Called by Location Services when the request to connect the - * client finishes successfully. At this point, you can - * request the current location or start periodic updates - */ - @Override - public void onConnected(Bundle dataBundle) - { - if (mLocationClient == null) - return; - - // Display the connection status - Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show(); - location_service_running = true; - - // If already requested, start periodic updates - if (mUpdatesRequested) - { - mLocationClient.requestLocationUpdates(mLocationRequest, this, null); - } - else - { - // Get last known location - mCurrentLocation = mLocationClient.getLastLocation(); - locationChanged = true; - } - } - - /** - * Called by Location Services if the connection to the - * location client drops because of an error. - */ - @Override - public void onDisconnected() - { - if (mLocationClient == null) - return; - - // Display the connection status - Toast.makeText(this, "Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show(); - - // If the client is connected - if (mLocationClient.isConnected()) - { - /* - * Remove location updates for a listener. - * The current Activity is the listener, so - * the argument is "this". - */ - mLocationClient.removeLocationUpdates(this); - } - - location_service_running = false; - } - - /** - * Called by Location Services if the attempt to - * Location Services fails. - */ - @Override - public void onConnectionFailed(ConnectionResult connectionResult) - { - /* - * Google Play services can resolve some errors it detects. - * If the error has a resolution, try sending an Intent to - * start a Google Play services activity that can resolve - * error. - */ - if (connectionResult.hasResolution()) - { - try - { - // Start an Activity that tries to resolve the error - connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST); - } - catch (IntentSender.SendIntentException e) - { - // Thrown if Google Play services cancelled the original PendingIntent - e.printStackTrace(); - } - } - else - { - /* - * If no resolution is available, display a dialog to the - * user with the error. - */ - Log.e("Connection failed", "error code: " + connectionResult.getErrorCode()); - } - } - - /** - * Sets the update interval at which location-based updates - * should occur - */ - public void onLocationSetInterval(int update_interval_in_ms, int distance_interval) - { - // Use high accuracy - if (mLocationRequest == null) - return; - - mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); - - if (update_interval_in_ms == 0) - mLocationRequest.setInterval(5 * 1000); // 5 seconds - else - mLocationRequest.setInterval(update_interval_in_ms); - - // Set the fastest update interval to 1 second - mLocationRequest.setFastestInterval(1000); - } - - /** - * Initializing methods for location based functionality. - */ - public void onLocationInit() - { - /* - * Create a new location client, using the enclosing class to - * handle callbacks. - */ - if (mLocationClient == null) - mLocationClient = new LocationClient(this, this, this); - - // Start with updates turned off - mUpdatesRequested = false; - - // Create the LocationRequest object - if (mLocationRequest == null) - mLocationRequest = LocationRequest.create(); - - onLocationSetInterval(0, 0); - } - - - /** - * Executed upon starting the {@link LocationClient}. - */ - public void onLocationStart() - { - if (mLocationClient == null) - return; - - mUpdatesRequested = true; - - // Connect the client. - mLocationClient.connect(); - } - - /** - * Free up location services resources. - */ - public void onLocationFree() - { - /* TODO/FIXME */ - } - - /** - * Executed upon stopping the location client. - * Does nothing if called when the client is not started. - */ - public void onLocationStop() - { - // Disconnecting the client invalidates it. - if (mLocationClient != null && mUpdatesRequested) - mLocationClient.disconnect(); - } - - /** - * Gets the latitude at the current location in degrees. - * - * @return the latitude at the current location. - */ - public double onLocationGetLatitude() - { - return mCurrentLocation.getLatitude(); - } - - /** - * Gets the longitude at the current location in degrees. - * - * @return the longitude at the current location. - */ - public double onLocationGetLongitude() - { - return mCurrentLocation.getLongitude(); - } - - /** - * Gets the horizontal accuracy of the current location - * in meters. (NOTE: There seems to be no vertical accuracy - * for a given location with the Android location API) - * - * @return the horizontal accuracy of the current position. - */ - public double onLocationGetHorizontalAccuracy() - { - return mCurrentLocation.getAccuracy(); - } - - /** - * Tells us whether the location listener callback has - * updated the current location since the last time - * we polled. - * - * @return true if location has changed, false if location has not changed. - */ - public boolean onLocationHasChanged() - { - boolean hasChanged = locationChanged; - - // Reset flag - if (hasChanged) - locationChanged = false; - - return hasChanged; - } - - // Define the callback method that receives location updates - @Override - public void onLocationChanged(Location location) - { - if (!location_service_running) - return; - - locationChanged = true; - mCurrentLocation = location; - - // Report to the UI that the location was updated - String msg = "Updated Location: " + location.getLatitude() + ", " + location.getLongitude(); - Log.i("RetroArch GPS", msg); - //Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); - } - - @Override - public void onPause() - { - // Save the current setting for updates - SharedPreferences prefs = UserPreferences.getPreferences(this); - SharedPreferences.Editor edit = prefs.edit(); - edit.putBoolean("LOCATION_UPDATES_ON", mUpdatesRequested); - edit.apply(); - - super.onPause(); - } - - @Override - public void onResume() - { - SharedPreferences prefs = UserPreferences.getPreferences(this); - SharedPreferences.Editor edit = prefs.edit(); - - /* - * Get any previous setting for location updates - * Gets "false" if an error occurs - */ - if (prefs.contains("LOCATION_UPDATES_ON")) - { - mUpdatesRequested = prefs.getBoolean("LOCATION_UPDATES_ON", false); - if (mUpdatesRequested) - location_service_running = true; - } - else // Otherwise, turn off location updates - { - edit.putBoolean("LOCATION_UPDATES_ON", false); - edit.apply(); - location_service_running = false; - } - - super.onResume(); - } - - @Override - public void onStop() - { - onLocationStop(); - super.onStop(); - } -} diff --git a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityPast.java b/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityPast.java deleted file mode 100644 index 4c11369ee9..0000000000 --- a/pkg/msvc/msvc-2017-android/msvc-2017-android.Packaging/src/com/retroarch/browser/retroactivity/RetroActivityPast.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.retroarch.browser.retroactivity; - -// For Android 2.3.x - -public final class RetroActivityPast extends RetroActivityCommon -{ -} From c540d83850e67ffcfa48fcba47e85629987e2e7d Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 15 Aug 2018 12:30:11 +0200 Subject: [PATCH 019/182] (MSVC 2017 Android) Update library name --- pkg/android/phoenix/msvc-2017-android.NativeActivity.vcxproj | 4 ++-- pkg/android/phoenix/msvc-2017-android.Packaging.androidproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/android/phoenix/msvc-2017-android.NativeActivity.vcxproj b/pkg/android/phoenix/msvc-2017-android.NativeActivity.vcxproj index cb5cb62c20..bc86a3ea31 100644 --- a/pkg/android/phoenix/msvc-2017-android.NativeActivity.vcxproj +++ b/pkg/android/phoenix/msvc-2017-android.NativeActivity.vcxproj @@ -69,12 +69,12 @@ {e27d73ec-6148-4817-b75c-adaa0c563939} Android - msvc-2017-android + retroarch-activity en-US 14.0 Android 3.0 - msvc-2017-android.NativeActivity + retroarch-activity.NativeActivity diff --git a/pkg/android/phoenix/msvc-2017-android.Packaging.androidproj b/pkg/android/phoenix/msvc-2017-android.Packaging.androidproj index 175d7df105..e61050d3de 100644 --- a/pkg/android/phoenix/msvc-2017-android.Packaging.androidproj +++ b/pkg/android/phoenix/msvc-2017-android.Packaging.androidproj @@ -35,7 +35,7 @@ - msvc-2017-android + retroarch-activity 14.0 1.0 {94b52983-76de-4545-a708-433c377727c7} From 1b544d687946ca8e5c2d9b2c0e303d47b98dfd88 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 15 Aug 2018 13:08:06 +0200 Subject: [PATCH 020/182] (AArch64) Add separate android phoenix dir --- pkg/android/phoenix64/.classpath | 9 + pkg/android/phoenix64/.gitignore | 5 + pkg/android/phoenix64/.project | 33 ++ pkg/android/phoenix64/AndroidManifest.xml | 43 +++ pkg/android/phoenix64/Readme.md | 3 + pkg/android/phoenix64/ant.properties | 17 + pkg/android/phoenix64/build.xml | 133 ++++++++ .../phoenix64/docs/Building in Eclipse.md | 45 +++ pkg/android/phoenix64/jni/Android.mk | 129 +++++++ pkg/android/phoenix64/jni/Application.mk | 42 +++ .../phoenix64/libs/googleplay/.classpath | 9 + .../phoenix64/libs/googleplay/.project | 33 ++ .../libs/googleplay/AndroidManifest.xml | 9 + .../phoenix64/libs/googleplay/README.txt | 17 + .../phoenix64/libs/googleplay/build.xml | 92 +++++ .../googleplay/libs/google-play-services.jar | Bin 0 -> 959413 bytes .../phoenix64/libs/googleplay/proguard.txt | 20 ++ .../libs/googleplay/project.properties | 15 + .../res/color/common_signin_btn_text_dark.xml | 18 + .../color/common_signin_btn_text_light.xml | 18 + ...common_signin_btn_icon_disabled_dark.9.png | Bin 0 -> 1811 bytes ..._signin_btn_icon_disabled_focus_dark.9.png | Bin 0 -> 1846 bytes ...signin_btn_icon_disabled_focus_light.9.png | Bin 0 -> 1846 bytes ...ommon_signin_btn_icon_disabled_light.9.png | Bin 0 -> 1811 bytes .../common_signin_btn_icon_focus_dark.9.png | Bin 0 -> 2100 bytes .../common_signin_btn_icon_focus_light.9.png | Bin 0 -> 2075 bytes .../common_signin_btn_icon_normal_dark.9.png | Bin 0 -> 2050 bytes .../common_signin_btn_icon_normal_light.9.png | Bin 0 -> 2049 bytes .../common_signin_btn_icon_pressed_dark.9.png | Bin 0 -> 2224 bytes ...common_signin_btn_icon_pressed_light.9.png | Bin 0 -> 2331 bytes ...common_signin_btn_text_disabled_dark.9.png | Bin 0 -> 1927 bytes ..._signin_btn_text_disabled_focus_dark.9.png | Bin 0 -> 1957 bytes ...signin_btn_text_disabled_focus_light.9.png | Bin 0 -> 1957 bytes ...ommon_signin_btn_text_disabled_light.9.png | Bin 0 -> 1927 bytes .../common_signin_btn_text_focus_dark.9.png | Bin 0 -> 2206 bytes .../common_signin_btn_text_focus_light.9.png | Bin 0 -> 2182 bytes .../common_signin_btn_text_normal_dark.9.png | Bin 0 -> 2185 bytes .../common_signin_btn_text_normal_light.9.png | Bin 0 -> 2158 bytes .../common_signin_btn_text_pressed_dark.9.png | Bin 0 -> 2374 bytes ...common_signin_btn_text_pressed_light.9.png | Bin 0 -> 2483 bytes .../ic_plusone_medium_off_client.png | Bin 0 -> 1187 bytes .../ic_plusone_small_off_client.png | Bin 0 -> 841 bytes .../ic_plusone_standard_off_client.png | Bin 0 -> 1498 bytes .../ic_plusone_tall_off_client.png | Bin 0 -> 1140 bytes ...common_signin_btn_icon_disabled_dark.9.png | Bin 0 -> 1202 bytes ..._signin_btn_icon_disabled_focus_dark.9.png | Bin 0 -> 1236 bytes ...signin_btn_icon_disabled_focus_light.9.png | Bin 0 -> 1236 bytes ...ommon_signin_btn_icon_disabled_light.9.png | Bin 0 -> 1202 bytes .../common_signin_btn_icon_focus_dark.9.png | Bin 0 -> 1389 bytes .../common_signin_btn_icon_focus_light.9.png | Bin 0 -> 1362 bytes .../common_signin_btn_icon_normal_dark.9.png | Bin 0 -> 1369 bytes .../common_signin_btn_icon_normal_light.9.png | Bin 0 -> 1345 bytes .../common_signin_btn_icon_pressed_dark.9.png | Bin 0 -> 1465 bytes ...common_signin_btn_icon_pressed_light.9.png | Bin 0 -> 1521 bytes ...common_signin_btn_text_disabled_dark.9.png | Bin 0 -> 1309 bytes ..._signin_btn_text_disabled_focus_dark.9.png | Bin 0 -> 1316 bytes ...signin_btn_text_disabled_focus_light.9.png | Bin 0 -> 1316 bytes ...ommon_signin_btn_text_disabled_light.9.png | Bin 0 -> 1309 bytes .../common_signin_btn_text_focus_dark.9.png | Bin 0 -> 1461 bytes .../common_signin_btn_text_focus_light.9.png | Bin 0 -> 1463 bytes .../common_signin_btn_text_normal_dark.9.png | Bin 0 -> 1463 bytes .../common_signin_btn_text_normal_light.9.png | Bin 0 -> 1455 bytes .../common_signin_btn_text_pressed_dark.9.png | Bin 0 -> 1556 bytes ...common_signin_btn_text_pressed_light.9.png | Bin 0 -> 1623 bytes .../ic_plusone_medium_off_client.png | Bin 0 -> 751 bytes .../ic_plusone_small_off_client.png | Bin 0 -> 581 bytes .../ic_plusone_standard_off_client.png | Bin 0 -> 996 bytes .../ic_plusone_tall_off_client.png | Bin 0 -> 789 bytes ...common_signin_btn_icon_disabled_dark.9.png | Bin 0 -> 2438 bytes ..._signin_btn_icon_disabled_focus_dark.9.png | Bin 0 -> 2457 bytes ...signin_btn_icon_disabled_focus_light.9.png | Bin 0 -> 2457 bytes ...ommon_signin_btn_icon_disabled_light.9.png | Bin 0 -> 2438 bytes .../common_signin_btn_icon_focus_dark.9.png | Bin 0 -> 2886 bytes .../common_signin_btn_icon_focus_light.9.png | Bin 0 -> 2908 bytes .../common_signin_btn_icon_normal_dark.9.png | Bin 0 -> 2847 bytes .../common_signin_btn_icon_normal_light.9.png | Bin 0 -> 2888 bytes .../common_signin_btn_icon_pressed_dark.9.png | Bin 0 -> 3133 bytes ...common_signin_btn_icon_pressed_light.9.png | Bin 0 -> 3301 bytes ...common_signin_btn_text_disabled_dark.9.png | Bin 0 -> 2569 bytes ..._signin_btn_text_disabled_focus_dark.9.png | Bin 0 -> 2571 bytes ...signin_btn_text_disabled_focus_light.9.png | Bin 0 -> 2571 bytes ...ommon_signin_btn_text_disabled_light.9.png | Bin 0 -> 2569 bytes .../common_signin_btn_text_focus_dark.9.png | Bin 0 -> 2939 bytes .../common_signin_btn_text_focus_light.9.png | Bin 0 -> 2947 bytes .../common_signin_btn_text_normal_dark.9.png | Bin 0 -> 2931 bytes .../common_signin_btn_text_normal_light.9.png | Bin 0 -> 2944 bytes .../common_signin_btn_text_pressed_dark.9.png | Bin 0 -> 3255 bytes ...common_signin_btn_text_pressed_light.9.png | Bin 0 -> 3384 bytes .../ic_plusone_medium_off_client.png | Bin 0 -> 1598 bytes .../ic_plusone_small_off_client.png | Bin 0 -> 1205 bytes .../ic_plusone_standard_off_client.png | Bin 0 -> 2074 bytes .../ic_plusone_tall_off_client.png | Bin 0 -> 1741 bytes ...common_signin_btn_icon_disabled_dark.9.png | Bin 0 -> 2438 bytes ..._signin_btn_icon_disabled_focus_dark.9.png | Bin 0 -> 2457 bytes ...signin_btn_icon_disabled_focus_light.9.png | Bin 0 -> 2457 bytes ...ommon_signin_btn_icon_disabled_light.9.png | Bin 0 -> 2438 bytes .../common_signin_btn_icon_focus_dark.9.png | Bin 0 -> 2886 bytes .../common_signin_btn_icon_focus_light.9.png | Bin 0 -> 2908 bytes .../common_signin_btn_icon_normal_dark.9.png | Bin 0 -> 2847 bytes .../common_signin_btn_icon_normal_light.9.png | Bin 0 -> 2888 bytes .../common_signin_btn_icon_pressed_dark.9.png | Bin 0 -> 3133 bytes ...common_signin_btn_icon_pressed_light.9.png | Bin 0 -> 3301 bytes ...common_signin_btn_text_disabled_dark.9.png | Bin 0 -> 2569 bytes ..._signin_btn_text_disabled_focus_dark.9.png | Bin 0 -> 2571 bytes ...signin_btn_text_disabled_focus_light.9.png | Bin 0 -> 2571 bytes ...ommon_signin_btn_text_disabled_light.9.png | Bin 0 -> 2569 bytes .../common_signin_btn_text_focus_dark.9.png | Bin 0 -> 2939 bytes .../common_signin_btn_text_focus_light.9.png | Bin 0 -> 2947 bytes .../common_signin_btn_text_normal_dark.9.png | Bin 0 -> 2931 bytes .../common_signin_btn_text_normal_light.9.png | Bin 0 -> 2944 bytes .../common_signin_btn_text_pressed_dark.9.png | Bin 0 -> 3255 bytes ...common_signin_btn_text_pressed_light.9.png | Bin 0 -> 3384 bytes .../ic_plusone_medium_off_client.png | Bin 0 -> 5828 bytes .../ic_plusone_small_off_client.png | Bin 0 -> 4279 bytes .../ic_plusone_standard_off_client.png | Bin 0 -> 7439 bytes .../ic_plusone_tall_off_client.png | Bin 0 -> 6204 bytes .../drawable/common_signin_btn_icon_dark.xml | 18 + .../drawable/common_signin_btn_icon_light.xml | 18 + .../drawable/common_signin_btn_text_dark.xml | 18 + .../drawable/common_signin_btn_text_light.xml | 18 + .../libs/googleplay/res/values-af/strings.xml | 31 ++ .../libs/googleplay/res/values-am/strings.xml | 31 ++ .../libs/googleplay/res/values-ar/strings.xml | 31 ++ .../libs/googleplay/res/values-be/strings.xml | 36 ++ .../libs/googleplay/res/values-bg/strings.xml | 31 ++ .../libs/googleplay/res/values-ca/strings.xml | 31 ++ .../libs/googleplay/res/values-cs/strings.xml | 31 ++ .../libs/googleplay/res/values-da/strings.xml | 31 ++ .../libs/googleplay/res/values-de/strings.xml | 31 ++ .../libs/googleplay/res/values-el/strings.xml | 31 ++ .../googleplay/res/values-en-rGB/strings.xml | 31 ++ .../googleplay/res/values-en-rIN/strings.xml | 31 ++ .../googleplay/res/values-es-rUS/strings.xml | 31 ++ .../libs/googleplay/res/values-es/strings.xml | 31 ++ .../googleplay/res/values-et-rEE/strings.xml | 31 ++ .../libs/googleplay/res/values-et/strings.xml | 31 ++ .../libs/googleplay/res/values-fa/strings.xml | 31 ++ .../libs/googleplay/res/values-fi/strings.xml | 31 ++ .../googleplay/res/values-fr-rCA/strings.xml | 31 ++ .../libs/googleplay/res/values-fr/strings.xml | 31 ++ .../libs/googleplay/res/values-hi/strings.xml | 31 ++ .../libs/googleplay/res/values-hr/strings.xml | 31 ++ .../libs/googleplay/res/values-hu/strings.xml | 31 ++ .../googleplay/res/values-hy-rAM/strings.xml | 31 ++ .../libs/googleplay/res/values-in/strings.xml | 31 ++ .../libs/googleplay/res/values-it/strings.xml | 31 ++ .../libs/googleplay/res/values-iw/strings.xml | 31 ++ .../libs/googleplay/res/values-ja/strings.xml | 31 ++ .../googleplay/res/values-ka-rGE/strings.xml | 31 ++ .../googleplay/res/values-km-rKH/strings.xml | 31 ++ .../libs/googleplay/res/values-ko/strings.xml | 31 ++ .../googleplay/res/values-lo-rLA/strings.xml | 31 ++ .../libs/googleplay/res/values-lt/strings.xml | 31 ++ .../libs/googleplay/res/values-lv/strings.xml | 31 ++ .../googleplay/res/values-mn-rMN/strings.xml | 31 ++ .../googleplay/res/values-ms-rMY/strings.xml | 31 ++ .../libs/googleplay/res/values-ms/strings.xml | 31 ++ .../libs/googleplay/res/values-nb/strings.xml | 31 ++ .../libs/googleplay/res/values-nl/strings.xml | 31 ++ .../libs/googleplay/res/values-pl/strings.xml | 31 ++ .../googleplay/res/values-pt-rBR/strings.xml | 31 ++ .../googleplay/res/values-pt-rPT/strings.xml | 31 ++ .../libs/googleplay/res/values-pt/strings.xml | 31 ++ .../libs/googleplay/res/values-ro/strings.xml | 31 ++ .../libs/googleplay/res/values-ru/strings.xml | 31 ++ .../libs/googleplay/res/values-sk/strings.xml | 31 ++ .../libs/googleplay/res/values-sl/strings.xml | 31 ++ .../libs/googleplay/res/values-sr/strings.xml | 31 ++ .../libs/googleplay/res/values-sv/strings.xml | 31 ++ .../libs/googleplay/res/values-sw/strings.xml | 31 ++ .../libs/googleplay/res/values-th/strings.xml | 31 ++ .../libs/googleplay/res/values-tl/strings.xml | 31 ++ .../libs/googleplay/res/values-tr/strings.xml | 31 ++ .../libs/googleplay/res/values-uk/strings.xml | 31 ++ .../libs/googleplay/res/values-vi/strings.xml | 31 ++ .../googleplay/res/values-zh-rCN/strings.xml | 31 ++ .../googleplay/res/values-zh-rHK/strings.xml | 31 ++ .../googleplay/res/values-zh-rTW/strings.xml | 31 ++ .../libs/googleplay/res/values-zu/strings.xml | 31 ++ .../libs/googleplay/res/values/ads_attrs.xml | 15 + .../libs/googleplay/res/values/colors.xml | 14 + .../libs/googleplay/res/values/maps_attrs.xml | 26 ++ .../libs/googleplay/res/values/strings.xml | 111 ++++++ .../libs/googleplay/res/values/version.xml | 4 + .../libs/googleplay/src/android/.readme | 2 + .../msvc-2017-android.NativeActivity.vcxproj | 273 +++++++++++++++ ...017-android.NativeActivity.vcxproj.filters | 8 + .../msvc-2017-android.Packaging.androidproj | 154 +++++++++ pkg/android/phoenix64/msvc-2017-android.sln | 72 ++++ pkg/android/phoenix64/proguard-project.txt | 20 ++ pkg/android/phoenix64/project.properties | 15 + .../res/drawable-hdpi/ic_launcher.png | Bin 0 -> 1329 bytes .../res/drawable-ldpi/ic_launcher.png | Bin 0 -> 690 bytes .../res/drawable-mdpi/ic_launcher.png | Bin 0 -> 853 bytes .../phoenix64/res/drawable-xhdpi/banner.png | Bin 0 -> 4423 bytes .../res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 1678 bytes .../res/drawable-xhdpi/ouya_icon.png | Bin 0 -> 19152 bytes .../res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 2524 bytes .../res/drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 3412 bytes pkg/android/phoenix64/res/drawable/banner.png | Bin 0 -> 4423 bytes .../browser/mainmenu/MainMenuActivity.java | 200 +++++++++++ .../browser/preferences/util/ConfigFile.java | 281 ++++++++++++++++ .../preferences/util/UserPreferences.java | 300 +++++++++++++++++ .../retroactivity/RetroActivityCamera.java | 225 +++++++++++++ .../retroactivity/RetroActivityCommon.java | 141 ++++++++ .../retroactivity/RetroActivityFuture.java | 87 +++++ .../retroactivity/RetroActivityIntent.java | 105 ++++++ .../retroactivity/RetroActivityLocation.java | 316 ++++++++++++++++++ .../retroactivity/RetroActivityPast.java | 7 + pkg/android/phoenix64/version_increment.py | 20 ++ 210 files changed, 4992 insertions(+) create mode 100644 pkg/android/phoenix64/.classpath create mode 100644 pkg/android/phoenix64/.gitignore create mode 100644 pkg/android/phoenix64/.project create mode 100644 pkg/android/phoenix64/AndroidManifest.xml create mode 100644 pkg/android/phoenix64/Readme.md create mode 100644 pkg/android/phoenix64/ant.properties create mode 100644 pkg/android/phoenix64/build.xml create mode 100644 pkg/android/phoenix64/docs/Building in Eclipse.md create mode 100644 pkg/android/phoenix64/jni/Android.mk create mode 100644 pkg/android/phoenix64/jni/Application.mk create mode 100644 pkg/android/phoenix64/libs/googleplay/.classpath create mode 100644 pkg/android/phoenix64/libs/googleplay/.project create mode 100644 pkg/android/phoenix64/libs/googleplay/AndroidManifest.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/README.txt create mode 100644 pkg/android/phoenix64/libs/googleplay/build.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/libs/google-play-services.jar create mode 100644 pkg/android/phoenix64/libs/googleplay/proguard.txt create mode 100644 pkg/android/phoenix64/libs/googleplay/project.properties create mode 100644 pkg/android/phoenix64/libs/googleplay/res/color/common_signin_btn_text_dark.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/color/common_signin_btn_text_light.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_disabled_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_normal_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_normal_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_pressed_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_icon_pressed_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_disabled_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_disabled_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_disabled_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_disabled_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_normal_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_normal_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_pressed_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/common_signin_btn_text_pressed_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/ic_plusone_medium_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/ic_plusone_small_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/ic_plusone_standard_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-hdpi/ic_plusone_tall_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_disabled_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_disabled_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_normal_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_normal_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_pressed_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_icon_pressed_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_disabled_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_disabled_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_disabled_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_disabled_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_normal_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_normal_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_pressed_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/common_signin_btn_text_pressed_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/ic_plusone_medium_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/ic_plusone_small_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/ic_plusone_standard_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-mdpi/ic_plusone_tall_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_disabled_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_normal_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_normal_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_pressed_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_icon_pressed_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_disabled_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_normal_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_normal_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_pressed_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/common_signin_btn_text_pressed_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/ic_plusone_medium_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/ic_plusone_small_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/ic_plusone_standard_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xhdpi/ic_plusone_tall_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_disabled_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_disabled_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_normal_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_normal_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_pressed_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_icon_pressed_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_disabled_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_focus_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_focus_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_normal_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_normal_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_pressed_dark.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/common_signin_btn_text_pressed_light.9.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/ic_plusone_medium_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/ic_plusone_small_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/ic_plusone_standard_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable-xxhdpi/ic_plusone_tall_off_client.png create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_icon_dark.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_icon_light.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_text_dark.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/drawable/common_signin_btn_text_light.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-af/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-am/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-ar/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-be/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-bg/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-ca/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-cs/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-da/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-de/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-el/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-en-rGB/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-en-rIN/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-es-rUS/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-es/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-et-rEE/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-et/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-fa/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-fi/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-fr-rCA/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-fr/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-hi/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-hr/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-hu/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-hy-rAM/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-in/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-it/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-iw/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-ja/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-ka-rGE/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-km-rKH/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-ko/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-lo-rLA/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-lt/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-lv/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-mn-rMN/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-ms-rMY/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-ms/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-nb/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-nl/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-pl/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-pt-rBR/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-pt-rPT/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-pt/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-ro/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-ru/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-sk/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-sl/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-sr/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-sv/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-sw/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-th/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-tl/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-tr/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-uk/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-vi/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-zh-rCN/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-zh-rHK/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-zh-rTW/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values-zu/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values/ads_attrs.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values/colors.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values/maps_attrs.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values/strings.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/res/values/version.xml create mode 100644 pkg/android/phoenix64/libs/googleplay/src/android/.readme create mode 100644 pkg/android/phoenix64/msvc-2017-android.NativeActivity.vcxproj create mode 100644 pkg/android/phoenix64/msvc-2017-android.NativeActivity.vcxproj.filters create mode 100644 pkg/android/phoenix64/msvc-2017-android.Packaging.androidproj create mode 100644 pkg/android/phoenix64/msvc-2017-android.sln create mode 100644 pkg/android/phoenix64/proguard-project.txt create mode 100644 pkg/android/phoenix64/project.properties create mode 100644 pkg/android/phoenix64/res/drawable-hdpi/ic_launcher.png create mode 100644 pkg/android/phoenix64/res/drawable-ldpi/ic_launcher.png create mode 100644 pkg/android/phoenix64/res/drawable-mdpi/ic_launcher.png create mode 100644 pkg/android/phoenix64/res/drawable-xhdpi/banner.png create mode 100644 pkg/android/phoenix64/res/drawable-xhdpi/ic_launcher.png create mode 100644 pkg/android/phoenix64/res/drawable-xhdpi/ouya_icon.png create mode 100644 pkg/android/phoenix64/res/drawable-xxhdpi/ic_launcher.png create mode 100644 pkg/android/phoenix64/res/drawable-xxxhdpi/ic_launcher.png create mode 100644 pkg/android/phoenix64/res/drawable/banner.png create mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/mainmenu/MainMenuActivity.java create mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/ConfigFile.java create mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/preferences/util/UserPreferences.java create mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCamera.java create mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityCommon.java create mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java create mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityIntent.java create mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityLocation.java create mode 100644 pkg/android/phoenix64/src/com/retroarch/browser/retroactivity/RetroActivityPast.java create mode 100644 pkg/android/phoenix64/version_increment.py diff --git a/pkg/android/phoenix64/.classpath b/pkg/android/phoenix64/.classpath new file mode 100644 index 0000000000..51769745b2 --- /dev/null +++ b/pkg/android/phoenix64/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pkg/android/phoenix64/.gitignore b/pkg/android/phoenix64/.gitignore new file mode 100644 index 0000000000..859bcd7938 --- /dev/null +++ b/pkg/android/phoenix64/.gitignore @@ -0,0 +1,5 @@ +/gen +/bin +/libs/*/*.so +/obj +/jni/modules/*.so diff --git a/pkg/android/phoenix64/.project b/pkg/android/phoenix64/.project new file mode 100644 index 0000000000..4af1961cac --- /dev/null +++ b/pkg/android/phoenix64/.project @@ -0,0 +1,33 @@ + + + RetroArch + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/pkg/android/phoenix64/AndroidManifest.xml b/pkg/android/phoenix64/AndroidManifest.xml new file mode 100644 index 0000000000..bbcfe2d309 --- /dev/null +++ b/pkg/android/phoenix64/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkg/android/phoenix64/Readme.md b/pkg/android/phoenix64/Readme.md new file mode 100644 index 0000000000..ce900d257e --- /dev/null +++ b/pkg/android/phoenix64/Readme.md @@ -0,0 +1,3 @@ +# Phoenix - Android front-end for RetroArch. + +- For instructions on importing the project correctly, please see the document, "Building in Eclipse.txt" within the docs folder. \ No newline at end of file diff --git a/pkg/android/phoenix64/ant.properties b/pkg/android/phoenix64/ant.properties new file mode 100644 index 0000000000..b0971e891e --- /dev/null +++ b/pkg/android/phoenix64/ant.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked into Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/pkg/android/phoenix64/build.xml b/pkg/android/phoenix64/build.xml new file mode 100644 index 0000000000..9698a04abf --- /dev/null +++ b/pkg/android/phoenix64/build.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkg/android/phoenix64/docs/Building in Eclipse.md b/pkg/android/phoenix64/docs/Building in Eclipse.md new file mode 100644 index 0000000000..bef2b9aea3 --- /dev/null +++ b/pkg/android/phoenix64/docs/Building in Eclipse.md @@ -0,0 +1,45 @@ +## Building the JNI-related files for Phoenix. + + 1. If you haven't already, install the Android NDK (http://developer.android.com/tools/sdk/ndk/index.html) + + 2. In the Phoenix root directory you should notice the folder named "jni". + + 3. Open Command Prompt/Terminal and cd into this directory. + + 4. Run ndk-build within this directory (just type "ndk-build" and hit Enter) and wait for everything to finish building. + + 5. All built libraries should now reside within the "libs" directory. + + 6. Continue to the next section of this document. + + + +## How to import the project into Eclipse and build the front-end: + + 1. Install the Android ADT plugin for Eclipse if you haven't. (http://developer.android.com/sdk/installing/installing-adt.html) + + 2. In Eclipse, do: File->Import->Existing Android Code Into Workspace. + + 3. Browse to the location of the folder named "phoenix" in the RetroArch repository and select it as the root dir. (as of writing, it is /android/phoenix). + + 4. You should see two projects have been found, "RetroArch" and "android-support-v7-appcompat". Import both of these. + + 5. Let Eclipse finish building the workspace, or whatever. + + 6. You should now be able to build it normally like any application. + + + +## Where do I place the built libretro cores? + +Simply place all built libretro cores within the directory [phoenix root]/assets/cores. Create this directory if it doesn't exist already. +After placing your cores there, they should show up within the core selection screen of the front-end. + +## Where do I place overlays, shaders and core info files? + +Core info files go in [phoenix root]/assets/info, GLSL shaders go in [phoenix root]/assets/shaders_glsl and overlays go in [phoenix root]/assets/overlays. If the folders don't exist, create them first. + +## Notes + +1. If you’re running into an issue where adding an existing Android project results in “Invalid project description”, please select a workspace location that doesn’t contain the Android projects. +2. If Eclipse still complains about missing appcompat, right-click on RetroArch->Properties->Android->Library->Add “android-support-v7-appcompat”, and then remove the old appcompat reference. diff --git a/pkg/android/phoenix64/jni/Android.mk b/pkg/android/phoenix64/jni/Android.mk new file mode 100644 index 0000000000..a44f14fa8b --- /dev/null +++ b/pkg/android/phoenix64/jni/Android.mk @@ -0,0 +1,129 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +RARCH_DIR := ../../../.. + +HAVE_NEON := 1 +HAVE_LOGGER := 0 +HAVE_VULKAN := 1 + +INCFLAGS := +DEFINES := + +LIBRETRO_COMM_DIR := $(RARCH_DIR)/libretro-common +DEPS_DIR := $(RARCH_DIR)/deps + +GIT_VERSION := $(shell git rev-parse --short HEAD 2>/dev/null) +ifneq ($(GIT_VERSION),) + DEFINES += -DHAVE_GIT_VERSION -DGIT_VERSION=$(GIT_VERSION) +endif + +include $(CLEAR_VARS) +ifeq ($(TARGET_ARCH),arm) + DEFINES += -DANDROID_ARM -marm + LOCAL_ARM_MODE := arm +endif + +ifeq ($(TARGET_ARCH),x86) + DEFINES += -DANDROID_X86 -DHAVE_SSSE3 +endif + +ifeq ($(TARGET_ARCH),x86_64) + DEFINES += -DANDROID_X64 +endif + +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) + +ifeq ($(HAVE_NEON),1) + DEFINES += -D__ARM_NEON__ -DHAVE_NEON + LOCAL_SRC_FILES += $(LIBRETRO_COMM_DIR)/audio/conversion/s16_to_float_neon.S.neon \ + $(LIBRETRO_COMM_DIR)/audio/conversion/float_to_s16_neon.S.neon \ + $(LIBRETRO_COMM_DIR)/audio/resampler/drivers/sinc_resampler_neon.S.neon \ + $(RARCH_DIR)/audio/drivers_resampler/cc_resampler_neon.S.neon +endif +DEFINES += -DANDROID_ARM_V7 +endif + +ifeq ($(TARGET_ARCH_ABI),arm64-v8a) + DEFINES += -DANDROID_AARCH64 +endif + +ifeq ($(TARGET_ARCH),mips) + DEFINES += -DANDROID_MIPS -D__mips__ -D__MIPSEL__ +endif + +LOCAL_MODULE := retroarch-activity + +LOCAL_SRC_FILES += $(RARCH_DIR)/griffin/griffin.c \ + $(RARCH_DIR)/griffin/griffin_cpp.cpp + +ifeq ($(HAVE_LOGGER), 1) + DEFINES += -DHAVE_LOGGER +endif +LOGGER_LDLIBS := -llog + +ifeq ($(GLES),3) + GLES_LIB := -lGLESv3 + DEFINES += -DHAVE_OPENGLES3 +else + GLES_LIB := -lGLESv2 + DEFINES += -DHAVE_OPENGLES2 +endif + +DEFINES += -DRARCH_MOBILE -DHAVE_GRIFFIN -DHAVE_STB_VORBIS -DHAVE_LANGEXTRA -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_OVERLAY -DHAVE_OPENGLES -DGLSL_DEBUG -DHAVE_DYLIB -DHAVE_EGL -DHAVE_GLSL -DHAVE_MENU -DHAVE_RGUI -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DINLINE=inline -DHAVE_THREADS -D__LIBRETRO__ -DHAVE_RSOUND -DHAVE_NETWORKGAMEPAD -DHAVE_NETWORKING -DRARCH_INTERNAL -DHAVE_FILTERS_BUILTIN -DHAVE_MATERIALUI -DHAVE_XMB -DHAVE_SHADERPIPELINE -DHAVE_LIBRETRODB -DHAVE_STB_FONT -DHAVE_IMAGEVIEWER -DHAVE_UPDATE_ASSETS -DHAVE_CC_RESAMPLER -DHAVE_MINIUPNPC -DHAVE_BUILTINMINIUPNPC -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -DHAVE_KEYMAPPER -DHAVE_NETWORKGAMEPAD -DHAVE_FLAC -DHAVE_DR_FLAC -DHAVE_DR_MP3 -DHAVE_CHD -DHAVE_RUNAHEAD -DENABLE_HLSL +DEFINES += -DWANT_IFADDRS + +ifeq ($(HAVE_VULKAN),1) +DEFINES += -DHAVE_VULKAN -DHAVE_SLANG -DHAVE_GLSLANG -DHAVE_SPIRV_CROSS -DWANT_GLSLANG -D__STDC_LIMIT_MACROS +endif +DEFINES += -DHAVE_7ZIP +DEFINES += -DHAVE_CHEEVOS +DEFINES += -DHAVE_SL +#DEFINES += -DHAVE_TINYALSA +DEFINES += -DFLAC_PACKAGE_VERSION="\"retroarch\"" -DHAVE_LROUND -DFLAC__HAS_OGG=0 + +LOCAL_CFLAGS += -Wall -std=gnu99 -pthread -Wno-unused-function -fno-stack-protector -funroll-loops $(DEFINES) +LOCAL_CPPFLAGS := -fexceptions -fpermissive -std=gnu++11 -fno-rtti -Wno-reorder $(DEFINES) + +# Let ndk-build set the optimization flags but remove -O3 like in cf3c3 +LOCAL_CFLAGS := $(subst -O3,-O2,$(LOCAL_CFLAGS)) + +LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -landroid -lEGL $(GLES_LIB) $(LOGGER_LDLIBS) -ldl +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/$(RARCH_DIR)/libretro-common/include/ \ + $(LOCAL_PATH)/$(RARCH_DIR)/deps \ + $(LOCAL_PATH)/$(RARCH_DIR)/deps/stb \ + $(LOCAL_PATH)/$(RARCH_DIR)/deps/7zip + + +LOCAL_CFLAGS += -I$(LOCAL_PATH)/$(DEPS_DIR)/stb/ +LOCAL_CFLAGS += -I$(LOCAL_PATH)/$(DEPS_DIR)/7zip/ +LOCAL_CXXFLAGS += -I$(LOCAL_PATH)/$(DEPS_DIR)/stb/ +LOCAL_CXXFLAGS += -I$(LOCAL_PATH)/$(DEPS_DIR)/7zip/ +LOCAL_CFLAGS += -I$(LOCAL_PATH)/$(DEPS_DIR)/libFLAC/include +LOCAL_CPPFLAGS += -I$(LOCAL_PATH)/$(DEPS_DIR)/libFLAC/include + +ifeq ($(HAVE_VULKAN),1) +INCFLAGS += $(LOCAL_PATH)/$(RARCH_DIR)/gfx/include + +LOCAL_C_INCLUDES += $(INCFLAGS) +LOCAL_CPPFLAGS += -I$(LOCAL_PATH)/$(DEPS_DIR)/glslang \ + -I$(LOCAL_PATH)/$(DEPS_DIR)/glslang/glslang/glslang/Public \ + -I$(LOCAL_PATH)/$(DEPS_DIR)/glslang/glslang/glslang/MachineIndependent \ + -I$(LOCAL_PATH)/$(DEPS_DIR)/glslang/glslang/SPIRV \ + -I$(LOCAL_PATH)/$(DEPS_DIR)/SPIRV-Cross + +LOCAL_CFLAGS += -Wno-sign-compare -Wno-unused-variable -Wno-parentheses +LOCAL_SRC_FILES += $(RARCH_DIR)/griffin/griffin_glslang.cpp +endif + +LOCAL_LDLIBS += -lOpenSLES -lz + +ifneq ($(SANITIZER),) + LOCAL_CFLAGS += -g -fsanitize=$(SANITIZER) -fno-omit-frame-pointer + LOCAL_CPPFLAGS += -g -fsanitize=$(SANITIZER) -fno-omit-frame-pointer + LOCAL_LDFLAGS += -fsanitize=$(SANITIZER) +endif + +include $(BUILD_SHARED_LIBRARY) diff --git a/pkg/android/phoenix64/jni/Application.mk b/pkg/android/phoenix64/jni/Application.mk new file mode 100644 index 0000000000..5058071558 --- /dev/null +++ b/pkg/android/phoenix64/jni/Application.mk @@ -0,0 +1,42 @@ +ifeq ($(GLES),3) + ifndef NDK_GL_HEADER_VER + APP_PLATFORM := android-18 + else + APP_PLATFORM := $(NDK_GL_HEADER_VER) + endif +else + ifndef NDK_NO_GL_HEADER_VER + APP_PLATFORM := android-9 + else + APP_PLATFORM := $(NDK_NO_GL_HEADER_VER) + endif +endif + +ifndef TARGET_ABIS + APP_ABI := arm64-v8a +else + APP_ABI := $(TARGET_ABIS) +endif + +# Run $NDK/toolchains/llvm-3.6/prebuilt/linux-x86_64/bin/asan_device_setup once +# for each AVD you use, replacing llvm-3.6 with the latest you have and +# linux-x86_64 with your host ABI. +ifneq ($(SANITIZER),) + # AddressSanitizer doesn't run on mips + ifndef TARGET_ABIS + APP_ABI := arm64-v8a + else + ifneq ($(findstring mips,$(TARGET_ABIS)),) + $(error "AddressSanitizer does not support mips.") + endif + endif + USE_CLANG := 1 +endif + +ifeq ($(USE_CLANG),1) + NDK_TOOLCHAIN_VERSION := clang + APP_CFLAGS := -Wno-invalid-source-encoding + APP_CPPFLAGS := -Wno-invalid-source-encoding +endif + +APP_STL := c++_static diff --git a/pkg/android/phoenix64/libs/googleplay/.classpath b/pkg/android/phoenix64/libs/googleplay/.classpath new file mode 100644 index 0000000000..51769745b2 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/.project b/pkg/android/phoenix64/libs/googleplay/.project new file mode 100644 index 0000000000..06ae985eaa --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/.project @@ -0,0 +1,33 @@ + + + google-play-services_lib + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/pkg/android/phoenix64/libs/googleplay/AndroidManifest.xml b/pkg/android/phoenix64/libs/googleplay/AndroidManifest.xml new file mode 100644 index 0000000000..99c96a3961 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/README.txt b/pkg/android/phoenix64/libs/googleplay/README.txt new file mode 100644 index 0000000000..32f8d5eb85 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/README.txt @@ -0,0 +1,17 @@ +Library Project including Google Play services client jar. + +This can be used by an Android project to use the API's provided +by Google Play services. + +There is technically no source, but the src folder is necessary +to ensure that the build system works. The content is actually +located in the libs/ directory. + + +USAGE: + +Make sure you import this Android library project into your IDE +and set this project as a dependency. + +Note that if you use proguard, you will want to include the +options from proguard.txt in your configuration. \ No newline at end of file diff --git a/pkg/android/phoenix64/libs/googleplay/build.xml b/pkg/android/phoenix64/libs/googleplay/build.xml new file mode 100644 index 0000000000..640264ba12 --- /dev/null +++ b/pkg/android/phoenix64/libs/googleplay/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkg/android/phoenix64/libs/googleplay/libs/google-play-services.jar b/pkg/android/phoenix64/libs/googleplay/libs/google-play-services.jar new file mode 100644 index 0000000000000000000000000000000000000000..dff6f7c241ed2a26178842b76e76b4d5262b35ac GIT binary patch literal 959413 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