1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2011-2017 - Daniel De Matteis
3  *  Copyright (C) 2014-2017 - Jean-André Santoni
4  *  Copyright (C) 2016-2019 - Brad Parker
5  *  Copyright (C) 2018 - Alfredo Monclús
6  *
7  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
8  *  of the GNU General Public License as published by the Free Software Found-
9  *  ation, either version 3 of the License, or (at your option) any later version.
10  *
11  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13  *  PURPOSE.  See the GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along with RetroArch.
16  *  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <stdlib.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <limits.h>
24 
25 #include <file/file_path.h>
26 #include <compat/posix_string.h>
27 #include <compat/strl.h>
28 #include <formats/image.h>
29 #include <string/stdstring.h>
30 #include <lists/string_list.h>
31 #include <gfx/math/matrix_4x4.h>
32 #include <streams/file_stream.h>
33 #include <encodings/utf.h>
34 #include <features/features_cpu.h>
35 
36 #ifdef HAVE_CONFIG_H
37 #include "../../config.h"
38 #endif
39 
40 #include "../../frontend/frontend_driver.h"
41 
42 #include "../menu_driver.h"
43 #include "../../gfx/gfx_animation.h"
44 #include "../menu_entries.h"
45 #include "../menu_input.h"
46 
47 #include "../../core_info.h"
48 #include "../../core.h"
49 
50 #include "../../input/input_osk.h"
51 
52 #include "../widgets/menu_filebrowser.h"
53 
54 #include "../../verbosity.h"
55 #include "../../configuration.h"
56 #include "../../playlist.h"
57 #include "../../retroarch.h"
58 
59 #include "../../tasks/tasks_internal.h"
60 
61 #ifdef HAVE_CHEEVOS
62 #include "../../cheevos/badges.h"
63 #endif
64 
65 #include "../../content.h"
66 
67 #define STRIPES_RIBBON_ROWS 64
68 #define STRIPES_RIBBON_COLS 64
69 #define STRIPES_RIBBON_VERTICES 2*STRIPES_RIBBON_COLS*STRIPES_RIBBON_ROWS-2*STRIPES_RIBBON_COLS
70 
71 #ifndef STRIPES_DELAY
72 #define STRIPES_DELAY 166
73 #endif
74 
75 #define BATTERY_LEVEL_CHECK_INTERVAL (30 * 1000000)
76 
77 #if 0
78 #define STRIPES_DEBUG
79 #endif
80 
81 /* NOTE: If you change this you HAVE to update
82  * stripes_alloc_node() and stripes_copy_node() */
83 typedef struct
84 {
85    float alpha;
86    float label_alpha;
87    float zoom;
88    float x;
89    float y;
90    float width;
91    uintptr_t icon;
92    uintptr_t content_icon;
93    char *fullpath;
94 } stripes_node_t;
95 
96 enum
97 {
98    STRIPES_TEXTURE_MAIN_MENU = 0,
99    STRIPES_TEXTURE_SETTINGS,
100    STRIPES_TEXTURE_HISTORY,
101    STRIPES_TEXTURE_FAVORITES,
102    STRIPES_TEXTURE_MUSICS,
103 #ifdef HAVE_FFMPEG
104    STRIPES_TEXTURE_MOVIES,
105 #endif
106 #ifdef HAVE_NETWORKING
107    STRIPES_TEXTURE_NETPLAY,
108    STRIPES_TEXTURE_ROOM,
109 /* stub these out until we have the icons
110    STRIPES_TEXTURE_ROOM_LAN,
111    STRIPES_TEXTURE_ROOM_MITM,*/
112 #endif
113 #ifdef HAVE_IMAGEVIEWER
114    STRIPES_TEXTURE_IMAGES,
115 #endif
116    STRIPES_TEXTURE_SETTING,
117    STRIPES_TEXTURE_SUBSETTING,
118    STRIPES_TEXTURE_ARROW,
119    STRIPES_TEXTURE_RUN,
120    STRIPES_TEXTURE_CLOSE,
121    STRIPES_TEXTURE_RESUME,
122    STRIPES_TEXTURE_SAVESTATE,
123    STRIPES_TEXTURE_LOADSTATE,
124    STRIPES_TEXTURE_UNDO,
125    STRIPES_TEXTURE_CORE_INFO,
126    STRIPES_TEXTURE_BLUETOOTH,
127    STRIPES_TEXTURE_WIFI,
128    STRIPES_TEXTURE_CORE_OPTIONS,
129    STRIPES_TEXTURE_INPUT_REMAPPING_OPTIONS,
130    STRIPES_TEXTURE_CHEAT_OPTIONS,
131    STRIPES_TEXTURE_DISK_OPTIONS,
132    STRIPES_TEXTURE_SHADER_OPTIONS,
133    STRIPES_TEXTURE_ACHIEVEMENT_LIST,
134    STRIPES_TEXTURE_SCREENSHOT,
135    STRIPES_TEXTURE_RELOAD,
136    STRIPES_TEXTURE_RENAME,
137    STRIPES_TEXTURE_FILE,
138    STRIPES_TEXTURE_FOLDER,
139    STRIPES_TEXTURE_ZIP,
140    STRIPES_TEXTURE_FAVORITE,
141    STRIPES_TEXTURE_ADD_FAVORITE,
142    STRIPES_TEXTURE_MUSIC,
143    STRIPES_TEXTURE_IMAGE,
144    STRIPES_TEXTURE_MOVIE,
145    STRIPES_TEXTURE_CORE,
146    STRIPES_TEXTURE_RDB,
147    STRIPES_TEXTURE_CURSOR,
148    STRIPES_TEXTURE_SWITCH_ON,
149    STRIPES_TEXTURE_SWITCH_OFF,
150    STRIPES_TEXTURE_CLOCK,
151    STRIPES_TEXTURE_BATTERY_FULL,
152    STRIPES_TEXTURE_BATTERY_CHARGING,
153    STRIPES_TEXTURE_POINTER,
154    STRIPES_TEXTURE_ADD,
155    STRIPES_TEXTURE_KEY,
156    STRIPES_TEXTURE_KEY_HOVER,
157    STRIPES_TEXTURE_DIALOG_SLICE,
158    STRIPES_TEXTURE_LAST
159 };
160 
161 enum
162 {
163    STRIPES_SYSTEM_TAB_MAIN = 0,
164    STRIPES_SYSTEM_TAB_SETTINGS,
165    STRIPES_SYSTEM_TAB_HISTORY,
166    STRIPES_SYSTEM_TAB_FAVORITES,
167    STRIPES_SYSTEM_TAB_MUSIC,
168 #ifdef HAVE_FFMPEG
169    STRIPES_SYSTEM_TAB_VIDEO,
170 #endif
171 #ifdef HAVE_IMAGEVIEWER
172    STRIPES_SYSTEM_TAB_IMAGES,
173 #endif
174 #ifdef HAVE_NETWORKING
175    STRIPES_SYSTEM_TAB_NETPLAY,
176 #endif
177    STRIPES_SYSTEM_TAB_ADD,
178 
179    /* End of this enum - use the last one to determine num of possible tabs */
180    STRIPES_SYSTEM_TAB_MAX_LENGTH
181 };
182 
183 typedef struct stripes_handle
184 {
185    bool mouse_show;
186 
187    uint8_t system_tab_end;
188    uint8_t tabs[STRIPES_SYSTEM_TAB_MAX_LENGTH];
189 
190    int depth;
191    int old_depth;
192    int icon_size;
193    int cursor_size;
194 
195    size_t categories_selection_ptr;
196    size_t categories_selection_ptr_old;
197    size_t selection_ptr_old;
198 
199    unsigned categories_active_idx;
200    unsigned categories_active_idx_old;
201    uintptr_t thumbnail;
202    uintptr_t left_thumbnail;
203    uintptr_t savestate_thumbnail;
204 
205    float x;
206    float alpha;
207    float thumbnail_width;
208    float thumbnail_height;
209    float left_thumbnail_width;
210    float left_thumbnail_height;
211    float savestate_thumbnail_width;
212    float savestate_thumbnail_height;
213    float above_subitem_offset;
214    float above_item_offset;
215    float active_item_factor;
216    float under_item_offset;
217    float shadow_offset;
218    float font_size;
219    float font2_size;
220 
221    float margins_screen_left;
222    float margins_screen_top;
223    float margins_setting_left;
224    float margins_title_left;
225    float margins_title_top;
226    float margins_title_bottom;
227    float margins_label_left;
228    float margins_label_top;
229    float icon_spacing_horizontal;
230    float icon_spacing_vertical;
231    float items_active_alpha;
232    float items_active_zoom;
233    float items_passive_alpha;
234    float items_passive_zoom;
235    float margins_dialog;
236    float margins_slice;
237    float textures_arrow_alpha;
238    float categories_x_pos;
239    float categories_angle;
240    float categories_active_y;
241    float categories_before_y;
242    float categories_after_y;
243    float categories_active_x;
244    float categories_before_x;
245    float categories_after_x;
246    float categories_passive_alpha;
247    float categories_passive_zoom;
248    float categories_passive_width;
249    float categories_active_zoom;
250    float categories_active_alpha;
251    float categories_active_width;
252 
253    char title_name[255];
254    char *box_message;
255    char *thumbnail_system;
256    char *thumbnail_content;
257    char *savestate_thumbnail_file_path;
258    char *thumbnail_file_path;
259    char *left_thumbnail_file_path;
260    char *bg_file_path;
261 
262    file_list_t selection_buf_old;   /* ptr alignment */
263    file_list_t horizontal_list;     /* ptr alignment */
264 
265    struct
266    {
267       uintptr_t bg;
268       uintptr_t list[STRIPES_TEXTURE_LAST];
269    } textures;
270 
271    stripes_node_t main_menu_node;
272 #ifdef HAVE_IMAGEVIEWER
273    stripes_node_t images_tab_node;
274 #endif
275    stripes_node_t music_tab_node;
276 #ifdef HAVE_FFMPEG
277    stripes_node_t video_tab_node;
278 #endif
279    stripes_node_t settings_tab_node;
280    stripes_node_t history_tab_node;
281    stripes_node_t favorites_tab_node;
282    stripes_node_t add_tab_node;
283    stripes_node_t netplay_tab_node;
284 
285    font_data_t *font;
286    font_data_t *font2;
287    video_font_raster_block_t raster_block;
288    video_font_raster_block_t raster_block2;
289 
290    void (*word_wrap)(char *dst, size_t dst_size, const char *src,
291       int line_width, int wideglyph_width, unsigned max_lines);
292 } stripes_handle_t;
293 
294 float stripes_scale_mod[8] = {
295    1, 1, 1, 1, 1, 1, 1, 1
296 };
297 
298 static float stripes_coord_shadow[] = {
299    0, 0, 0,
300    0, 0, 0,
301    0, 0, 0,
302    0, 0, 0,
303    0, 0, 0, 0
304 };
305 
306 static float stripes_coord_black[] = {
307    0, 0, 0,
308    0, 0, 0,
309    0, 0, 0,
310    0, 0, 0,
311    0, 0, 0, 0
312 };
313 
314 static float stripes_coord_white[] = {
315    1, 1, 1,
316    1, 1, 1,
317    1, 1, 1,
318    1, 1, 1,
319    1, 1, 1, 1
320 };
321 
322 static float stripes_item_color[] = {
323    1, 1, 1,
324    1, 1, 1,
325    1, 1, 1,
326    1, 1, 1,
327    1, 1, 1, 1
328 };
329 
HueToRGB(float v1,float v2,float vH)330 static float HueToRGB(float v1, float v2, float vH)
331 {
332    if (vH < 0)
333       vH += 1;
334 
335    if (vH > 1)
336       vH -= 1;
337 
338    if ((6 * vH) < 1)
339       return (v1 + (v2 - v1) * 6 * vH);
340 
341    if ((2 * vH) < 1)
342       return v2;
343 
344    if ((3 * vH) < 2)
345       return (v1 + (v2 - v1) * ((2.0f / 3) - vH) * 6);
346 
347    return v1;
348 }
349 
HSLToRGB(float H,float S,float L,float * rgb)350 static void HSLToRGB(float H, float S, float L, float *rgb) {
351    if (S == 0)
352       rgb[0] = rgb[1] = rgb[2] = L;
353    else
354    {
355       float v1, v2;
356 
357       v2 = (L < 0.5) ? (L * (1 + S)) : ((L + S) - (L * S));
358       v1 = 2 * L - v2;
359 
360       rgb[0] = HueToRGB(v1, v2, H + (1.0f / 3));
361       rgb[1] = HueToRGB(v1, v2, H);
362       rgb[2] = HueToRGB(v1, v2, H - (1.0f / 3));
363    }
364 }
365 
366 static void stripes_calculate_visible_range(const stripes_handle_t *stripes,
367       unsigned height, size_t list_size, unsigned current,
368       unsigned *first, unsigned *last);
369 
stripes_theme_ident(void)370 const char* stripes_theme_ident(void)
371 {
372    settings_t *settings = config_get_ptr();
373    switch (settings->uints.menu_xmb_theme)
374    {
375       case XMB_ICON_THEME_FLATUI:
376          return "flatui";
377       case XMB_ICON_THEME_RETROACTIVE:
378          return "retroactive";
379       case XMB_ICON_THEME_RETROSYSTEM:
380          return "retrosystem";
381       case XMB_ICON_THEME_PIXEL:
382          return "pixel";
383       case XMB_ICON_THEME_NEOACTIVE:
384          return "neoactive";
385       case XMB_ICON_THEME_SYSTEMATIC:
386          return "systematic";
387       case XMB_ICON_THEME_DOTART:
388          return "dot-art";
389       case XMB_ICON_THEME_CUSTOM:
390          return "custom";
391       case XMB_ICON_THEME_MONOCHROME_INVERTED:
392          return "monochrome-inverted";
393       case XMB_ICON_THEME_MONOCHROME:
394       default:
395          break;
396    }
397 
398    return "monochrome";
399 }
400 
401 /* NOTE: This exists because calloc()ing stripes_node_t is expensive
402  * when you can have big lists like MAME and fba playlists */
stripes_alloc_node(void)403 static stripes_node_t *stripes_alloc_node(void)
404 {
405    stripes_node_t *node = (stripes_node_t*)malloc(sizeof(*node));
406 
407    node->alpha = node->label_alpha  = 0;
408    node->zoom  = node->x = node->y  = 0;
409    node->icon  = node->content_icon = 0;
410    node->fullpath = NULL;
411 
412    return node;
413 }
414 
stripes_free_node(stripes_node_t * node)415 static void stripes_free_node(stripes_node_t *node)
416 {
417     if (!node)
418         return;
419 
420     if (node->fullpath)
421         free(node->fullpath);
422 
423     node->fullpath = NULL;
424 
425     free(node);
426 }
427 
428 /**
429  * @brief frees all stripes_node_t in a file_list_t
430  *
431  * file_list_t asumes userdata holds a simple structure and
432  * free()'s it. Can't change this at the time because other
433  * code depends on this behavior.
434  *
435  * @param list
436  * @param actiondata whether to free actiondata too
437  */
stripes_free_list_nodes(file_list_t * list,bool actiondata)438 static void stripes_free_list_nodes(file_list_t *list, bool actiondata)
439 {
440    unsigned i, size = list ? list->size : 0;
441 
442    for (i = 0; i < size; ++i)
443    {
444       stripes_free_node((stripes_node_t*)file_list_get_userdata_at_offset(list, i));
445 
446       list->list[i].userdata = NULL;
447 
448       if (actiondata)
449          file_list_free_actiondata(list, i);
450    }
451 }
452 
stripes_copy_node(const stripes_node_t * old_node)453 static stripes_node_t *stripes_copy_node(const stripes_node_t *old_node)
454 {
455    stripes_node_t *new_node = (stripes_node_t*)malloc(sizeof(*new_node));
456 
457    *new_node            = *old_node;
458    new_node->fullpath   = old_node->fullpath ? strdup(old_node->fullpath) : NULL;
459 
460    return new_node;
461 }
462 
stripes_thumbnails_ident(char pos)463 static const char *stripes_thumbnails_ident(char pos)
464 {
465    char folder          = 0;
466    settings_t *settings = config_get_ptr();
467 
468    if (pos == 'R')
469       folder = settings->uints.gfx_thumbnails;
470    if (pos == 'L')
471       folder = settings->uints.menu_left_thumbnails;
472 
473    switch (folder)
474    {
475       case 1:
476          return "Named_Snaps";
477       case 2:
478          return "Named_Titles";
479       case 3:
480          return "Named_Boxarts";
481       case 0:
482       default:
483          break;
484    }
485 
486    return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
487 }
488 
stripes_list_get_selection(void * data)489 static size_t stripes_list_get_selection(void *data)
490 {
491    stripes_handle_t *stripes      = (stripes_handle_t*)data;
492 
493    if (!stripes)
494       return 0;
495 
496    return stripes->categories_selection_ptr;
497 }
498 
stripes_list_get_size(void * data,enum menu_list_type type)499 static size_t stripes_list_get_size(void *data, enum menu_list_type type)
500 {
501    stripes_handle_t *stripes       = (stripes_handle_t*)data;
502 
503    switch (type)
504    {
505       case MENU_LIST_PLAIN:
506          return menu_entries_get_stack_size(0);
507       case MENU_LIST_HORIZONTAL:
508          return stripes->horizontal_list.size;
509       case MENU_LIST_TABS:
510          return stripes->system_tab_end;
511    }
512 
513    return 0;
514 }
515 
stripes_list_get_entry(void * data,enum menu_list_type type,unsigned i)516 static void *stripes_list_get_entry(void *data,
517       enum menu_list_type type, unsigned i)
518 {
519    size_t list_size        = 0;
520    stripes_handle_t *stripes       = (stripes_handle_t*)data;
521 
522    switch (type)
523    {
524       case MENU_LIST_PLAIN:
525          {
526             file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0);
527             list_size  = menu_entries_get_stack_size(0);
528             if (i < list_size)
529                return (void*)&menu_stack->list[i];
530          }
531          break;
532       case MENU_LIST_HORIZONTAL:
533          list_size = stripes->horizontal_list.size;
534          if (i < list_size)
535             return (void*)&stripes->horizontal_list.list[i];
536          break;
537       default:
538          break;
539    }
540 
541    return NULL;
542 }
543 
stripes_item_y(const stripes_handle_t * stripes,int i,size_t current)544 static INLINE float stripes_item_y(const stripes_handle_t *stripes, int i, size_t current)
545 {
546    float iy = stripes->icon_spacing_vertical;
547 
548    if (i < (int)current)
549       if (stripes->depth > 1)
550          iy *= (i - (int)current + stripes->above_subitem_offset);
551       else
552          iy *= (i - (int)current + stripes->above_item_offset);
553    else
554       iy    *= (i - (int)current + stripes->under_item_offset);
555 
556    if (i == (int)current)
557       iy = stripes->icon_spacing_vertical * stripes->active_item_factor;
558 
559    return iy;
560 }
561 
stripes_draw_icon(void * userdata,unsigned video_width,unsigned video_height,bool xmb_shadows_enable,int icon_size,math_matrix_4x4 * mymat,uintptr_t texture,float x,float y,unsigned width,unsigned height,float alpha,float rotation,float scale_factor,float * color,float shadow_offset)562 static void stripes_draw_icon(
563       void *userdata,
564       unsigned video_width,
565       unsigned video_height,
566       bool xmb_shadows_enable,
567       int icon_size,
568       math_matrix_4x4 *mymat,
569       uintptr_t texture,
570       float x,
571       float y,
572       unsigned width,
573       unsigned height,
574       float alpha,
575       float rotation,
576       float scale_factor,
577       float *color,
578       float shadow_offset)
579 {
580    gfx_display_ctx_draw_t draw;
581    struct video_coords coords;
582 
583    if (
584          (x < (-icon_size / 2.0f)) ||
585          (x > width)               ||
586          (y < (icon_size  / 2.0f)) ||
587          (y > height + icon_size)
588       )
589       return;
590 
591    coords.vertices      = 4;
592    coords.vertex        = NULL;
593    coords.tex_coord     = NULL;
594    coords.lut_tex_coord = NULL;
595 
596    draw.width           = icon_size;
597    draw.height          = icon_size;
598    draw.rotation        = rotation;
599    draw.scale_factor    = scale_factor;
600 #if defined(VITA) || defined(WIIU)
601    draw.width          *= scale_factor;
602    draw.height         *= scale_factor;
603 #endif
604    draw.coords          = &coords;
605    draw.matrix_data     = mymat;
606    draw.texture         = texture;
607    draw.prim_type       = GFX_DISPLAY_PRIM_TRIANGLESTRIP;
608    draw.pipeline_id     = 0;
609 
610    if (xmb_shadows_enable)
611    {
612       gfx_display_set_alpha(stripes_coord_shadow, color[3] * 0.35f);
613 
614       coords.color      = stripes_coord_shadow;
615       draw.x            = x + shadow_offset;
616       draw.y            = height - y - shadow_offset;
617 
618 #if defined(VITA) || defined(WIIU)
619       if (scale_factor < 1)
620       {
621          draw.x         = draw.x + (icon_size-draw.width)/2;
622          draw.y         = draw.y + (icon_size-draw.width)/2;
623       }
624 #endif
625       if (draw.height > 0 && draw.width > 0)
626          if (dispctx && dispctx->draw)
627             dispctx->draw(&draw, userdata, video_width, video_height);
628    }
629 
630    coords.color         = (const float*)color;
631    draw.x               = x;
632    draw.y               = height - y;
633 
634 #if defined(VITA) || defined(WIIU)
635    if (scale_factor < 1)
636    {
637       draw.x            = draw.x + (icon_size-draw.width)/2;
638       draw.y            = draw.y + (icon_size-draw.width)/2;
639    }
640 #endif
641    if (draw.height > 0 && draw.width > 0)
642       if (dispctx && dispctx->draw)
643          dispctx->draw(&draw, userdata, video_width, video_height);
644 }
645 
stripes_draw_text(bool xmb_shadows_enable,stripes_handle_t * stripes,const char * str,float x,float y,float scale_factor,float alpha,enum text_alignment text_align,unsigned width,unsigned height,font_data_t * font)646 static void stripes_draw_text(
647       bool xmb_shadows_enable,
648       stripes_handle_t *stripes,
649       const char *str, float x,
650       float y, float scale_factor, float alpha,
651       enum text_alignment text_align,
652       unsigned width, unsigned height, font_data_t* font)
653 {
654    uint32_t color;
655    uint8_t a8;
656    settings_t *settings;
657 
658    if (alpha > stripes->alpha)
659       alpha = stripes->alpha;
660 
661    a8       = 255 * alpha;
662 
663    /* Avoid drawing 100% transparent text */
664    if (a8 == 0)
665       return;
666 
667    settings = config_get_ptr();
668    color = FONT_COLOR_RGBA(
669          settings->uints.menu_font_color_red,
670          settings->uints.menu_font_color_green,
671          settings->uints.menu_font_color_blue, a8);
672 
673    gfx_display_draw_text(font, str, x, y,
674          width, height, color, text_align, scale_factor,
675          xmb_shadows_enable,
676          stripes->shadow_offset, false);
677 }
678 
stripes_messagebox(void * data,const char * message)679 static void stripes_messagebox(void *data, const char *message)
680 {
681    stripes_handle_t *stripes = (stripes_handle_t*)data;
682 
683    if (!stripes || string_is_empty(message))
684       return;
685 
686    stripes->box_message = strdup(message);
687 }
688 
689 /* Returns the OSK key at a given position */
stripes_osk_ptr_at_pos(void * data,int x,int y,unsigned width,unsigned height)690 static int stripes_osk_ptr_at_pos(
691       void *data,
692       int x,
693       int y,
694       unsigned width,
695       unsigned height)
696 {
697    unsigned i;
698    int ptr_width, ptr_height;
699    stripes_handle_t *stripes = (stripes_handle_t*)data;
700 
701    if (!stripes)
702       return -1;
703 
704    ptr_width  = width  / 11;
705    ptr_height = height / 10;
706 
707    if (ptr_width >= ptr_height)
708       ptr_width = ptr_height;
709 
710    for (i = 0; i < 44; i++)
711    {
712       int line_y    = (i / 11)*height/10.0;
713       int ptr_x     = width/2.0 - (11*ptr_width)/2.0 + (i % 11) * ptr_width;
714       int ptr_y     = height/2.0 + ptr_height*1.5 + line_y - ptr_height;
715 
716       if (x > ptr_x && x < ptr_x + ptr_width
717        && y > ptr_y && y < ptr_y + ptr_height)
718          return i;
719    }
720 
721    return -1;
722 }
723 
stripes_render_messagebox_internal(stripes_handle_t * stripes,void * userdata,unsigned video_width,unsigned video_height,const char * message)724 static void stripes_render_messagebox_internal(
725       stripes_handle_t *stripes,
726       void *userdata,
727       unsigned video_width,
728       unsigned video_height,
729       const char *message)
730 {
731    unsigned i, y_position;
732    int x, y, longest = 0, longest_width = 0;
733    float line_height        = 0;
734    struct string_list *list = !string_is_empty(message)
735       ? string_split(message, "\n") : NULL;
736    gfx_display_t            *p_disp  = disp_get_ptr();
737    gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
738 
739    if (!list || !stripes || !stripes->font)
740    {
741       if (list)
742          string_list_free(list);
743       return;
744    }
745 
746    if (list->elems == 0)
747       goto end;
748 
749    line_height      = stripes->font->size * 1.2;
750 
751    y_position       = video_height / 2;
752    if (menu_input_dialog_get_display_kb())
753       y_position    = video_height / 4;
754 
755    x                = video_width  / 2;
756    y                = y_position - (list->size-1) * line_height / 2;
757 
758    /* find the longest line width */
759    for (i = 0; i < list->size; i++)
760    {
761       const char *msg  = list->elems[i].data;
762       int len          = (int)utf8len(msg);
763 
764       if (len > longest)
765       {
766          longest       = len;
767          longest_width = font_driver_get_message_width(
768                stripes->font, msg, strlen(msg), 1);
769       }
770    }
771 
772    if (dispctx && dispctx->blend_begin)
773       dispctx->blend_begin(userdata);
774 
775    gfx_display_draw_texture_slice(
776          userdata,
777          video_width,
778          video_height,
779          x - longest_width / 2 - stripes->margins_dialog,
780          y + stripes->margins_slice - stripes->margins_dialog,
781          256, 256,
782          longest_width + stripes->margins_dialog * 2,
783          line_height * list->size + stripes->margins_dialog * 2,
784          video_width,
785          video_height,
786          NULL,
787          stripes->margins_slice, 1.0f,
788          stripes->textures.list[STRIPES_TEXTURE_DIALOG_SLICE]);
789 
790    for (i = 0; i < list->size; i++)
791    {
792       const char *msg = list->elems[i].data;
793 
794       if (msg)
795          gfx_display_draw_text(stripes->font, msg,
796                x - longest_width / 2.0f,
797                y + (i + 0.75f) * line_height,
798                video_width,
799                video_height,
800                0x444444ff,
801                TEXT_ALIGN_LEFT,
802                1.0f, false, 0.0f, false);
803    }
804 
805    if (menu_input_dialog_get_display_kb())
806       gfx_display_draw_keyboard(
807             p_disp,
808             userdata,
809             video_width,
810             video_height,
811             stripes->textures.list[STRIPES_TEXTURE_KEY_HOVER],
812             stripes->font,
813             input_event_get_osk_grid(),
814             input_event_get_osk_ptr(),
815             0xffffffff);
816 
817 end:
818    string_list_free(list);
819 }
820 
stripes_update_thumbnail_path(void * data,unsigned i,char pos)821 static void stripes_update_thumbnail_path(void *data, unsigned i, char pos)
822 {
823    menu_entry_t entry;
824    unsigned entry_type            = 0;
825    char new_path[PATH_MAX_LENGTH];
826    settings_t     *settings       = config_get_ptr();
827    stripes_handle_t     *stripes  = (stripes_handle_t*)data;
828    playlist_t     *playlist       = NULL;
829    const char    *dir_thumbnails  = settings->paths.directory_thumbnails;
830 
831    if (!stripes || string_is_empty(dir_thumbnails))
832       goto end;
833 
834    new_path[0]                    = '\0';
835 
836    MENU_ENTRY_INIT(entry);
837    menu_entry_get(&entry, 0, i, NULL, true);
838 
839    entry_type = entry.type;
840 
841    if (entry_type == FILE_TYPE_IMAGEVIEWER || entry_type == FILE_TYPE_IMAGE)
842    {
843       file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
844       stripes_node_t *node = (stripes_node_t*)
845          file_list_get_userdata_at_offset(selection_buf, i);
846 
847       if (!string_is_empty(node->fullpath) &&
848          (pos == 'R' || (pos == 'L' && string_is_equal(stripes_thumbnails_ident('R'),
849             msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))))
850       {
851          if (!string_is_empty(entry.path))
852             fill_pathname_join(
853                   new_path,
854                   node->fullpath,
855                   entry.path,
856                   sizeof(new_path));
857 
858          goto end;
859       }
860    }
861    else if (filebrowser_get_type() != FILEBROWSER_NONE)
862    {
863       video_driver_texture_unload(&stripes->thumbnail);
864       goto end;
865    }
866 
867    playlist = playlist_get_cached();
868 
869    if (playlist)
870    {
871       const struct playlist_entry *entry  = NULL;
872       playlist_get_index(playlist, i, &entry);
873 
874       if (string_is_equal(entry->core_name, "imageviewer"))
875       {
876          if (pos == 'R' || (pos == 'L' && string_is_equal(stripes_thumbnails_ident('R'),
877             msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))))
878          {
879             if (!string_is_empty(entry->label))
880                strlcpy(new_path, entry->label,
881                      sizeof(new_path));
882             goto end;
883          }
884          else
885          {
886             video_driver_texture_unload(&stripes->left_thumbnail);
887             goto end;
888          }
889       }
890    }
891 
892    /* Append thumbnail system directory */
893    if (!string_is_empty(stripes->thumbnail_system))
894       fill_pathname_join(
895             new_path,
896             dir_thumbnails,
897             stripes->thumbnail_system,
898             sizeof(new_path));
899 
900    if (!string_is_empty(new_path))
901    {
902       char tmp_new2[PATH_MAX_LENGTH];
903 
904       tmp_new2[0]                    = '\0';
905 
906       /* Append Named_Snaps/Named_Boxarts/Named_Titles */
907       if (pos ==  'R')
908          fill_pathname_join(tmp_new2, new_path,
909                stripes_thumbnails_ident('R'), sizeof(tmp_new2));
910       if (pos ==  'L')
911          fill_pathname_join(tmp_new2, new_path,
912                stripes_thumbnails_ident('L'), sizeof(tmp_new2));
913 
914       strlcpy(new_path, tmp_new2, sizeof(new_path));
915    }
916 
917    /* Scrub characters that are not cross-platform and/or violate the
918     * No-Intro filename standard:
919     * http://datomatic.no-intro.org/stuff/The%20Official%20No-Intro%20Convention%20(20071030).zip
920     * Replace these characters in the entry name with underscores.
921     */
922    if (!string_is_empty(stripes->thumbnail_content))
923    {
924       char tmp_new[PATH_MAX_LENGTH];
925       char *scrub_char_pointer       = NULL;
926       char            *tmp           = strdup(stripes->thumbnail_content);
927 
928       tmp_new[0]                     = '\0';
929 
930       while ((scrub_char_pointer = strpbrk(tmp, "&*/:`\"<>?\\|")))
931          *scrub_char_pointer = '_';
932 
933       /* Look for thumbnail file with this scrubbed filename */
934 
935       fill_pathname_join(tmp_new, new_path, tmp, sizeof(tmp_new));
936 
937       if (!string_is_empty(tmp_new))
938          strlcpy(new_path,
939                tmp_new, sizeof(new_path));
940 
941       free(tmp);
942    }
943 
944    /* Append png extension */
945    if (!string_is_empty(new_path))
946       strlcat(new_path, ".png", sizeof(new_path));
947 
948 end:
949    if (stripes && !string_is_empty(new_path))
950    {
951       if (pos == 'R')
952          stripes->thumbnail_file_path = strdup(new_path);
953       if (pos == 'L')
954          stripes->left_thumbnail_file_path = strdup(new_path);
955    }
956 }
957 
stripes_update_savestate_thumbnail_path(void * data,unsigned i)958 static void stripes_update_savestate_thumbnail_path(void *data, unsigned i)
959 {
960    menu_entry_t entry;
961    settings_t     *settings = config_get_ptr();
962    stripes_handle_t     *stripes    = (stripes_handle_t*)data;
963 
964    if (!stripes)
965       return;
966 
967    MENU_ENTRY_INIT(entry);
968    menu_entry_get(&entry, 0, i, NULL, true);
969 
970    if (!string_is_empty(stripes->savestate_thumbnail_file_path))
971       free(stripes->savestate_thumbnail_file_path);
972    stripes->savestate_thumbnail_file_path = NULL;
973 
974    if (!string_is_empty(entry.label))
975    {
976       if (     (settings->bools.savestate_thumbnail_enable)
977             && ((string_is_equal(entry.label, "state_slot"))
978                || (string_is_equal(entry.label, "loadstate"))
979                || (string_is_equal(entry.label, "savestate"))))
980       {
981          char path[8024];
982          global_t         *global = global_get_ptr();
983 
984          path[0] = '\0';
985 
986          if (global)
987          {
988             int state_slot = settings->ints.state_slot;
989 
990             if (state_slot > 0)
991                snprintf(path, sizeof(path), "%s%d",
992                      global->name.savestate, state_slot);
993             else if (state_slot < 0)
994                fill_pathname_join_delim(path,
995                      global->name.savestate, "auto", '.', sizeof(path));
996             else
997                strlcpy(path, global->name.savestate, sizeof(path));
998          }
999 
1000          strlcat(path, ".png", sizeof(path));
1001 
1002          if (path_is_valid(path))
1003          {
1004             if (!string_is_empty(stripes->savestate_thumbnail_file_path))
1005                free(stripes->savestate_thumbnail_file_path);
1006             stripes->savestate_thumbnail_file_path = strdup(path);
1007          }
1008       }
1009    }
1010 }
1011 
stripes_update_thumbnail_image(void * data)1012 static void stripes_update_thumbnail_image(void *data)
1013 {
1014    stripes_handle_t *stripes = (stripes_handle_t*)data;
1015    bool supports_rgba        = video_driver_supports_rgba();
1016    if (!stripes)
1017       return;
1018 
1019    if (!(string_is_empty(stripes->thumbnail_file_path)))
1020       {
1021          if (path_is_valid(stripes->thumbnail_file_path))
1022             task_push_image_load(stripes->thumbnail_file_path,
1023                   supports_rgba, 0,
1024                   gfx_display_handle_thumbnail_upload, NULL);
1025          else
1026             video_driver_texture_unload(&stripes->thumbnail);
1027 
1028          free(stripes->thumbnail_file_path);
1029          stripes->thumbnail_file_path = NULL;
1030       }
1031 
1032    if (!(string_is_empty(stripes->left_thumbnail_file_path)))
1033       {
1034          if (path_is_valid(stripes->left_thumbnail_file_path))
1035             task_push_image_load(stripes->left_thumbnail_file_path,
1036                   supports_rgba, 0,
1037                   gfx_display_handle_left_thumbnail_upload, NULL);
1038          else
1039             video_driver_texture_unload(&stripes->left_thumbnail);
1040 
1041          free(stripes->left_thumbnail_file_path);
1042          stripes->left_thumbnail_file_path = NULL;
1043       }
1044 }
1045 
stripes_refresh_thumbnail_image(void * data,unsigned i)1046 static void stripes_refresh_thumbnail_image(void *data, unsigned i)
1047 {
1048    stripes_update_thumbnail_image(data);
1049 }
1050 
stripes_set_thumbnail_system(void * data,char * s,size_t len)1051 static void stripes_set_thumbnail_system(void *data, char*s, size_t len)
1052 {
1053    stripes_handle_t *stripes = (stripes_handle_t*)data;
1054    if (!stripes)
1055       return;
1056 
1057    if (!string_is_empty(stripes->thumbnail_system))
1058       free(stripes->thumbnail_system);
1059    stripes->thumbnail_system = strdup(s);
1060 }
1061 
stripes_get_thumbnail_system(void * data,char * s,size_t len)1062 static void stripes_get_thumbnail_system(void *data, char*s, size_t len)
1063 {
1064    stripes_handle_t *stripes = (stripes_handle_t*)data;
1065    if (!stripes)
1066       return;
1067 
1068    if (!string_is_empty(stripes->thumbnail_system))
1069       strlcpy(s, stripes->thumbnail_system, len);
1070 }
1071 
stripes_reset_thumbnail_content(void * data)1072 static void stripes_reset_thumbnail_content(void *data)
1073 {
1074    stripes_handle_t *stripes = (stripes_handle_t*)data;
1075    if (!stripes)
1076       return;
1077    if (!string_is_empty(stripes->thumbnail_content))
1078       free(stripes->thumbnail_content);
1079    stripes->thumbnail_content = NULL;
1080 }
1081 
stripes_set_thumbnail_content(void * data,char * s,size_t len)1082 static void stripes_set_thumbnail_content(void *data, char *s, size_t len)
1083 {
1084    stripes_handle_t *stripes = (stripes_handle_t*)data;
1085    if (!stripes)
1086       return;
1087    if (!string_is_empty(stripes->thumbnail_content))
1088       free(stripes->thumbnail_content);
1089    stripes->thumbnail_content = strdup(s);
1090 }
1091 
stripes_update_savestate_thumbnail_image(void * data)1092 static void stripes_update_savestate_thumbnail_image(void *data)
1093 {
1094    stripes_handle_t *stripes = (stripes_handle_t*)data;
1095    if (!stripes)
1096       return;
1097 
1098    if (path_is_valid(stripes->savestate_thumbnail_file_path))
1099       task_push_image_load(stripes->savestate_thumbnail_file_path,
1100             video_driver_supports_rgba(), 0,
1101             gfx_display_handle_savestate_thumbnail_upload, NULL);
1102    else
1103       video_driver_texture_unload(&stripes->savestate_thumbnail);
1104 }
1105 
stripes_get_system_tab(stripes_handle_t * stripes,unsigned i)1106 static unsigned stripes_get_system_tab(stripes_handle_t *stripes, unsigned i)
1107 {
1108    if (i <= stripes->system_tab_end)
1109    {
1110       return stripes->tabs[i];
1111    }
1112    return UINT_MAX;
1113 }
1114 
stripes_selection_pointer_changed(stripes_handle_t * stripes,bool allow_animations)1115 static void stripes_selection_pointer_changed(
1116       stripes_handle_t *stripes, bool allow_animations)
1117 {
1118    uintptr_t tag;
1119    unsigned i, end, height;
1120    menu_entry_t entry;
1121    size_t num                 = 0;
1122    int threshold              = 0;
1123    file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
1124    size_t selection           = menu_navigation_get_selection();
1125    const char *thumb_ident    = stripes_thumbnails_ident('R');
1126    const char *lft_thumb_ident= stripes_thumbnails_ident('L');
1127 
1128    if (!stripes)
1129       return;
1130 
1131    MENU_ENTRY_INIT(entry);
1132    menu_entry_get(&entry, 0, selection, NULL, true);
1133 
1134    end       = (unsigned)menu_entries_get_size();
1135    threshold = stripes->icon_size * 10;
1136 
1137    video_driver_get_size(NULL, &height);
1138 
1139    tag       = (uintptr_t)selection_buf;
1140 
1141    gfx_animation_kill_by_tag(&tag);
1142    menu_entries_ctl(MENU_ENTRIES_CTL_SET_START, &num);
1143 
1144    for (i = 0; i < end; i++)
1145    {
1146       float iy, real_iy;
1147       float ia         = stripes->items_passive_alpha;
1148       float iz         = stripes->items_passive_zoom;
1149       stripes_node_t *node = (stripes_node_t*)
1150          file_list_get_userdata_at_offset(selection_buf, i);
1151 
1152       if (!node)
1153          continue;
1154 
1155       iy      = stripes_item_y(stripes, i, selection);
1156       real_iy = iy + stripes->margins_screen_top;
1157 
1158       if (     (!allow_animations)
1159             || (real_iy < -threshold
1160             || real_iy > height+threshold))
1161       {
1162          node->alpha = node->label_alpha = ia;
1163          node->y = iy;
1164          node->zoom = iz;
1165       }
1166       else
1167       {
1168          gfx_animation_ctx_entry_t anim_entry;
1169 
1170          anim_entry.duration     = STRIPES_DELAY;
1171          anim_entry.target_value = ia;
1172          anim_entry.subject      = &node->alpha;
1173          anim_entry.easing_enum  = EASING_OUT_QUAD;
1174          anim_entry.tag          = tag;
1175          anim_entry.cb           = NULL;
1176 
1177          gfx_animation_push(&anim_entry);
1178 
1179          anim_entry.subject      = &node->label_alpha;
1180 
1181          gfx_animation_push(&anim_entry);
1182 
1183          anim_entry.target_value = iz;
1184          anim_entry.subject      = &node->zoom;
1185 
1186          gfx_animation_push(&anim_entry);
1187 
1188          anim_entry.target_value = iy;
1189          anim_entry.subject      = &node->y;
1190 
1191          gfx_animation_push(&anim_entry);
1192       }
1193    }
1194 }
1195 
stripes_list_open_old(stripes_handle_t * stripes,file_list_t * list,int dir,size_t current)1196 static void stripes_list_open_old(stripes_handle_t *stripes,
1197       file_list_t *list, int dir, size_t current)
1198 {
1199    unsigned i, height = 0;
1200    int        threshold = stripes->icon_size * 10;
1201    size_t           end = list ? list->size : NULL;
1202 
1203    video_driver_get_size(NULL, &height);
1204 
1205    for (i = 0; i < end; i++)
1206    {
1207       float ia = 0;
1208       float real_y;
1209       stripes_node_t *node = (stripes_node_t*)
1210          file_list_get_userdata_at_offset(list, i);
1211 
1212       if (!node)
1213          continue;
1214 
1215       if (i == current)
1216          ia = stripes->items_active_alpha;
1217       if (dir == -1)
1218          ia = 0;
1219 
1220       real_y = node->y + stripes->margins_screen_top;
1221 
1222       if (real_y < -threshold || real_y > height+threshold)
1223       {
1224          node->alpha = ia;
1225          node->label_alpha = 0;
1226          node->x = stripes->icon_size * dir * -2;
1227       }
1228       else
1229       {
1230          gfx_animation_ctx_entry_t anim_entry;
1231 
1232          anim_entry.duration     = STRIPES_DELAY;
1233          anim_entry.target_value = ia;
1234          anim_entry.subject      = &node->alpha;
1235          anim_entry.easing_enum  = EASING_OUT_QUAD;
1236          anim_entry.tag          = (uintptr_t)list;
1237          anim_entry.cb           = NULL;
1238 
1239          gfx_animation_push(&anim_entry);
1240 
1241          anim_entry.target_value = 0;
1242          anim_entry.subject      = &node->label_alpha;
1243 
1244          gfx_animation_push(&anim_entry);
1245 
1246          anim_entry.target_value = stripes->icon_size * dir * -2;
1247          anim_entry.subject      = &node->x;
1248 
1249          gfx_animation_push(&anim_entry);
1250       }
1251    }
1252 }
1253 
stripes_list_open_new(stripes_handle_t * stripes,file_list_t * list,int dir,size_t current)1254 static void stripes_list_open_new(stripes_handle_t *stripes,
1255       file_list_t *list, int dir, size_t current)
1256 {
1257    unsigned i, height;
1258    unsigned stripes_system_tab = 0;
1259    size_t skip                 = 0;
1260    int        threshold        = stripes->icon_size * 10;
1261    size_t           end        = list ? list->size : NULL;
1262 
1263    video_driver_get_size(NULL, &height);
1264 
1265    for (i = 0; i < end; i++)
1266    {
1267       float ia;
1268       float real_y;
1269       stripes_node_t *node = (stripes_node_t*)
1270          file_list_get_userdata_at_offset(list, i);
1271 
1272       if (!node)
1273          continue;
1274 
1275       if (dir == 1 || (dir == -1 && i != current))
1276          node->alpha = 0;
1277 
1278       if (dir == 1 || dir == -1)
1279          node->label_alpha = 0;
1280 
1281       node->x = stripes->icon_size * dir * 2;
1282       node->y = stripes_item_y(stripes, i, current);
1283       node->zoom = stripes->categories_passive_zoom;
1284 
1285       real_y = node->y + stripes->margins_screen_top;
1286 
1287       if (i == current)
1288          node->zoom = stripes->categories_active_zoom;
1289 
1290       ia    = stripes->items_passive_alpha;
1291       if (i == current)
1292          ia = stripes->items_active_alpha;
1293 
1294       if (real_y < -threshold || real_y > height+threshold)
1295       {
1296          node->alpha = node->label_alpha = ia;
1297          node->x = 0;
1298       }
1299       else
1300       {
1301          gfx_animation_ctx_entry_t anim_entry;
1302 
1303          anim_entry.duration     = STRIPES_DELAY;
1304          anim_entry.target_value = ia;
1305          anim_entry.subject      = &node->alpha;
1306          anim_entry.easing_enum  = EASING_OUT_QUAD;
1307          anim_entry.tag          = (uintptr_t)list;
1308          anim_entry.cb           = NULL;
1309 
1310          gfx_animation_push(&anim_entry);
1311 
1312          anim_entry.subject      = &node->label_alpha;
1313 
1314          gfx_animation_push(&anim_entry);
1315 
1316          anim_entry.target_value = 0;
1317          anim_entry.subject      = &node->x;
1318 
1319          gfx_animation_push(&anim_entry);
1320       }
1321    }
1322 
1323    stripes->old_depth = stripes->depth;
1324    menu_entries_ctl(MENU_ENTRIES_CTL_SET_START, &skip);
1325 
1326    stripes_system_tab = stripes_get_system_tab(stripes,
1327          (unsigned)stripes->categories_selection_ptr);
1328 
1329    if (stripes_system_tab <= STRIPES_SYSTEM_TAB_SETTINGS)
1330    {
1331       if (stripes->depth < 4)
1332          stripes_reset_thumbnail_content(stripes);
1333       stripes_update_thumbnail_path(stripes, 0, 'R');
1334       stripes_update_thumbnail_image(stripes);
1335       stripes_update_thumbnail_path(stripes, 0, 'L');
1336       stripes_update_thumbnail_image(stripes);
1337    }
1338 }
1339 
stripes_node_allocate_userdata(stripes_handle_t * stripes,unsigned i)1340 static stripes_node_t *stripes_node_allocate_userdata(
1341       stripes_handle_t *stripes, unsigned i)
1342 {
1343    stripes_node_t *tmp  = NULL;
1344    stripes_node_t *node = stripes_alloc_node();
1345 
1346    if (!node)
1347    {
1348       RARCH_ERR("XMB node could not be allocated.\n");
1349       return NULL;
1350    }
1351 
1352    node->alpha = stripes->categories_passive_alpha;
1353    node->zoom  = stripes->categories_passive_zoom;
1354 
1355    if ((i + stripes->system_tab_end) == stripes->categories_active_idx)
1356    {
1357       node->alpha = stripes->categories_active_alpha;
1358       node->zoom  = stripes->categories_active_zoom;
1359    }
1360 
1361    tmp = (stripes_node_t*)file_list_get_userdata_at_offset(
1362          &stripes->horizontal_list, i);
1363    stripes_free_node(tmp);
1364 
1365    stripes->horizontal_list.list[i].userdata = node;
1366 
1367    return node;
1368 }
1369 
stripes_get_userdata_from_horizontal_list(stripes_handle_t * stripes,unsigned i)1370 static stripes_node_t* stripes_get_userdata_from_horizontal_list(
1371       stripes_handle_t *stripes, unsigned i)
1372 {
1373    return (stripes_node_t*)
1374       file_list_get_userdata_at_offset(&stripes->horizontal_list, i);
1375 }
1376 
stripes_push_animations(stripes_node_t * node,uintptr_t tag,float ia,float ix)1377 static void stripes_push_animations(stripes_node_t *node,
1378       uintptr_t tag, float ia, float ix)
1379 {
1380    gfx_animation_ctx_entry_t anim_entry;
1381 
1382    anim_entry.duration     = STRIPES_DELAY;
1383    anim_entry.target_value = ia;
1384    anim_entry.subject      = &node->alpha;
1385    anim_entry.easing_enum  = EASING_OUT_QUAD;
1386    anim_entry.tag          = tag;
1387    anim_entry.cb           = NULL;
1388 
1389    gfx_animation_push(&anim_entry);
1390 
1391    anim_entry.subject      = &node->label_alpha;
1392 
1393    gfx_animation_push(&anim_entry);
1394 
1395    anim_entry.target_value = ix;
1396    anim_entry.subject      = &node->x;
1397 
1398    gfx_animation_push(&anim_entry);
1399 }
1400 
stripes_list_switch_old(stripes_handle_t * stripes,file_list_t * list,int dir,size_t current)1401 static void stripes_list_switch_old(stripes_handle_t *stripes,
1402       file_list_t *list, int dir, size_t current)
1403 {
1404    unsigned i, first, last, height;
1405    size_t end = list ? list->size : NULL;
1406    float ix   = -stripes->icon_spacing_horizontal * dir;
1407    float ia   = 0;
1408 
1409    first = 0;
1410    last  = end > 0 ? end - 1 : 0;
1411 
1412    video_driver_get_size(NULL, &height);
1413    stripes_calculate_visible_range(stripes, height, end,
1414          current, &first, &last);
1415 
1416    for (i = 0; i < end; i++)
1417    {
1418       stripes_node_t *node = (stripes_node_t*)
1419          file_list_get_userdata_at_offset(list, i);
1420 
1421       if (!node)
1422          continue;
1423 
1424       if (i >= first && i <= last)
1425          stripes_push_animations(node, (uintptr_t)list, ia, ix);
1426       else
1427       {
1428          node->alpha = node->label_alpha = ia;
1429          node->x     = ix;
1430       }
1431    }
1432 }
1433 
stripes_list_switch_new(stripes_handle_t * stripes,file_list_t * list,int dir,size_t current)1434 static void stripes_list_switch_new(stripes_handle_t *stripes,
1435       file_list_t *list, int dir, size_t current)
1436 {
1437    unsigned i, first, last, height;
1438    size_t end           = 0;
1439    settings_t *settings = config_get_ptr();
1440 
1441    if (settings->bools.menu_dynamic_wallpaper_enable)
1442    {
1443       char path[PATH_MAX_LENGTH];
1444       char       *tmp  = string_replace_substring(stripes->title_name, "/", " ");
1445 
1446       path[0]          = '\0';
1447 
1448       if (tmp)
1449       {
1450          fill_pathname_join_noext(
1451                path,
1452                settings->paths.directory_dynamic_wallpapers,
1453                tmp,
1454                sizeof(path));
1455          free(tmp);
1456       }
1457 
1458       strlcat(path, ".png", sizeof(path));
1459 
1460       if (!path_is_valid(path))
1461          fill_pathname_application_special(path, sizeof(path),
1462                APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_BG);
1463 
1464        if (!string_is_equal(path, stripes->bg_file_path))
1465        {
1466            if (path_is_valid(path))
1467            {
1468               task_push_image_load(path,
1469                     video_driver_supports_rgba(), 0,
1470                   menu_display_handle_wallpaper_upload, NULL);
1471               if (!string_is_empty(stripes->bg_file_path))
1472                  free(stripes->bg_file_path);
1473               stripes->bg_file_path = strdup(path);
1474            }
1475        }
1476    }
1477 
1478    end   = list ? list->size : NULL;
1479    first = 0;
1480    last  = end > 0 ? end - 1 : 0;
1481 
1482    video_driver_get_size(NULL, &height);
1483    stripes_calculate_visible_range(stripes, height, end, current, &first, &last);
1484 
1485    for (i = 0; i < end; i++)
1486    {
1487       stripes_node_t *node = (stripes_node_t*)
1488          file_list_get_userdata_at_offset(list, i);
1489       float ia         = stripes->items_passive_alpha;
1490 
1491       if (!node)
1492          continue;
1493 
1494       node->x           = stripes->icon_spacing_horizontal * dir;
1495       node->alpha       = 0;
1496       node->label_alpha = 0;
1497 
1498       if (i == current)
1499          ia = stripes->items_active_alpha;
1500 
1501       if (i >= first && i <= last)
1502          stripes_push_animations(node, (uintptr_t)list, ia, 0);
1503       else
1504       {
1505          node->x     = 0;
1506          node->alpha = node->label_alpha = ia;
1507       }
1508    }
1509 }
1510 
stripes_set_title(stripes_handle_t * stripes)1511 static void stripes_set_title(stripes_handle_t *stripes)
1512 {
1513    if (stripes->categories_selection_ptr <= stripes->system_tab_end)
1514    {
1515       menu_entries_get_title(stripes->title_name, sizeof(stripes->title_name));
1516    }
1517    else
1518    {
1519       const char *path = stripes->horizontal_list.list[
1520             stripes->categories_selection_ptr - (stripes->system_tab_end + 1)].path;
1521       if (!path)
1522          return;
1523 
1524       fill_pathname_base_noext(
1525             stripes->title_name, path, sizeof(stripes->title_name));
1526    }
1527 }
1528 
stripes_get_node(stripes_handle_t * stripes,unsigned i)1529 static stripes_node_t* stripes_get_node(stripes_handle_t *stripes, unsigned i)
1530 {
1531    switch (stripes_get_system_tab(stripes, i))
1532    {
1533       case STRIPES_SYSTEM_TAB_SETTINGS:
1534          return &stripes->settings_tab_node;
1535 #ifdef HAVE_IMAGEVIEWER
1536       case STRIPES_SYSTEM_TAB_IMAGES:
1537          return &stripes->images_tab_node;
1538 #endif
1539       case STRIPES_SYSTEM_TAB_MUSIC:
1540          return &stripes->music_tab_node;
1541 #ifdef HAVE_FFMPEG
1542       case STRIPES_SYSTEM_TAB_VIDEO:
1543          return &stripes->video_tab_node;
1544 #endif
1545       case STRIPES_SYSTEM_TAB_HISTORY:
1546          return &stripes->history_tab_node;
1547       case STRIPES_SYSTEM_TAB_FAVORITES:
1548          return &stripes->favorites_tab_node;
1549 #ifdef HAVE_NETWORKING
1550       case STRIPES_SYSTEM_TAB_NETPLAY:
1551          return &stripes->netplay_tab_node;
1552 #endif
1553       case STRIPES_SYSTEM_TAB_ADD:
1554          return &stripes->add_tab_node;
1555       default:
1556          if (i > stripes->system_tab_end)
1557             return stripes_get_userdata_from_horizontal_list(
1558                   stripes, i - (stripes->system_tab_end + 1));
1559    }
1560 
1561    return &stripes->main_menu_node;
1562 }
1563 
stripes_list_switch_horizontal_list(stripes_handle_t * stripes)1564 static void stripes_list_switch_horizontal_list(stripes_handle_t *stripes)
1565 {
1566    unsigned j;
1567    size_t list_size = stripes_list_get_size(stripes, MENU_LIST_HORIZONTAL)
1568       + stripes->system_tab_end;
1569 
1570    for (j = 0; j <= list_size; j++)
1571    {
1572       gfx_animation_ctx_entry_t entry;
1573       float ia                    = stripes->categories_passive_alpha;
1574       float iz                    = stripes->categories_passive_zoom;
1575       float iw                    = stripes->categories_passive_width;
1576       float ix                    = stripes->categories_before_x;
1577       float iy                    = stripes->categories_before_y;
1578       stripes_node_t *node            = stripes_get_node(stripes, j);
1579 
1580       if (!node)
1581          continue;
1582 
1583       if (j == stripes->categories_active_idx)
1584       {
1585          ia = stripes->categories_active_alpha;
1586          iz = stripes->categories_active_zoom;
1587          iw = stripes->categories_active_width;
1588          ix = stripes->categories_active_x;
1589          iy = stripes->categories_active_y;
1590       }
1591       else if (j < stripes->categories_active_idx)
1592       {
1593          ix = stripes->categories_before_x;
1594          iy = stripes->categories_before_y;
1595       }
1596       else if (j > stripes->categories_active_idx)
1597       {
1598          ix = stripes->categories_after_x;
1599          iy = stripes->categories_after_y;
1600       }
1601 
1602       entry.duration     = STRIPES_DELAY;
1603       entry.target_value = ia;
1604       entry.subject      = &node->alpha;
1605       entry.easing_enum  = EASING_OUT_QUAD;
1606       /* TODO/FIXME - integer conversion resulted in change of sign */
1607       entry.tag          = -1;
1608       entry.cb           = NULL;
1609 
1610       gfx_animation_push(&entry);
1611 
1612       entry.target_value = iz;
1613       entry.subject      = &node->zoom;
1614 
1615       gfx_animation_push(&entry);
1616 
1617       entry.target_value = iy;
1618       entry.subject      = &node->y;
1619 
1620       gfx_animation_push(&entry);
1621 
1622       entry.target_value = ix;
1623       entry.subject      = &node->x;
1624 
1625       gfx_animation_push(&entry);
1626 
1627       entry.target_value = iw;
1628       entry.subject      = &node->width;
1629 
1630       gfx_animation_push(&entry);
1631    }
1632 }
1633 
stripes_list_switch(stripes_handle_t * stripes)1634 static void stripes_list_switch(stripes_handle_t *stripes)
1635 {
1636    gfx_animation_ctx_entry_t anim_entry;
1637    int dir                    = -1;
1638    file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
1639    size_t selection           = menu_navigation_get_selection();
1640    settings_t *settings = config_get_ptr();
1641 
1642    if (stripes->categories_selection_ptr > stripes->categories_selection_ptr_old)
1643       dir = 1;
1644 
1645    stripes->categories_active_idx += dir;
1646 
1647    stripes_list_switch_horizontal_list(stripes);
1648 
1649    anim_entry.duration     = STRIPES_DELAY;
1650    anim_entry.target_value = stripes->categories_passive_width
1651       * -(float)stripes->categories_selection_ptr;
1652    anim_entry.subject      = &stripes->categories_x_pos;
1653    anim_entry.easing_enum  = EASING_OUT_QUAD;
1654    /* TODO/FIXME - integer conversion resulted in change of sign */
1655    anim_entry.tag          = -1;
1656    anim_entry.cb           = NULL;
1657 
1658    if (anim_entry.subject)
1659       gfx_animation_push(&anim_entry);
1660 
1661    dir = -1;
1662    if (stripes->categories_selection_ptr > stripes->categories_selection_ptr_old)
1663       dir = 1;
1664 
1665    stripes_list_switch_old(stripes,
1666          &stripes->selection_buf_old,
1667          dir, stripes->selection_ptr_old);
1668 
1669    /* Check if we are to have horizontal animations. */
1670    if (settings->bools.menu_horizontal_animation)
1671       stripes_list_switch_new(stripes, selection_buf, dir, selection);
1672    stripes->categories_active_idx_old = (unsigned)stripes->categories_selection_ptr;
1673 
1674    if (!string_is_equal(stripes_thumbnails_ident('R'),
1675             msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
1676    {
1677       menu_entry_t entry;
1678 
1679       MENU_ENTRY_INIT(entry);
1680       menu_entry_get(&entry, 0, selection, NULL, true);
1681 
1682       if (!string_is_empty(entry.path))
1683          stripes_set_thumbnail_content(stripes, entry.path, 0 /* will be ignored */);
1684 
1685       stripes_update_thumbnail_path(stripes, 0, 'R');
1686       stripes_update_thumbnail_image(stripes);
1687    }
1688    if (!string_is_equal(stripes_thumbnails_ident('L'),
1689             msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
1690    {
1691       menu_entry_t entry;
1692 
1693       MENU_ENTRY_INIT(entry);
1694       menu_entry_get(&entry, 0, selection, NULL, true);
1695 
1696       if (!string_is_empty(entry.path))
1697          stripes_set_thumbnail_content(stripes, entry.path, 0 /* will be ignored */);
1698 
1699       stripes_update_thumbnail_path(stripes, 0, 'L');
1700       stripes_update_thumbnail_image(stripes);
1701    }
1702 }
1703 
stripes_list_open_horizontal_list(stripes_handle_t * stripes)1704 static void stripes_list_open_horizontal_list(stripes_handle_t *stripes)
1705 {
1706    unsigned j;
1707    size_t list_size = stripes_list_get_size(stripes, MENU_LIST_HORIZONTAL)
1708       + stripes->system_tab_end;
1709 
1710    for (j = 0; j <= list_size; j++)
1711    {
1712       gfx_animation_ctx_entry_t anim_entry;
1713       float ia          = 0;
1714       stripes_node_t *node  = stripes_get_node(stripes, j);
1715 
1716       if (!node)
1717          continue;
1718 
1719       if (j == stripes->categories_active_idx)
1720          ia = stripes->categories_active_alpha;
1721       else if (stripes->depth <= 1)
1722          ia = stripes->categories_passive_alpha;
1723 
1724       anim_entry.duration     = STRIPES_DELAY;
1725       anim_entry.target_value = ia;
1726       anim_entry.subject      = &node->alpha;
1727       anim_entry.easing_enum  = EASING_OUT_QUAD;
1728       /* TODO/FIXME - integer conversion resulted in change of sign */
1729       anim_entry.tag          = -1;
1730       anim_entry.cb           = NULL;
1731 
1732       if (anim_entry.subject)
1733          gfx_animation_push(&anim_entry);
1734    }
1735 }
1736 
stripes_context_destroy_horizontal_list(stripes_handle_t * stripes)1737 static void stripes_context_destroy_horizontal_list(stripes_handle_t *stripes)
1738 {
1739    unsigned i;
1740    size_t list_size = stripes_list_get_size(stripes, MENU_LIST_HORIZONTAL);
1741 
1742    for (i = 0; i < list_size; i++)
1743    {
1744       const char *path = NULL;
1745       stripes_node_t *node = stripes_get_userdata_from_horizontal_list(stripes, i);
1746 
1747       if (!node)
1748          continue;
1749 
1750       if (!(path = stripes->horizontal_list.list[i].path))
1751          continue;
1752 
1753       if (string_ends_with_size(path, ".lpl",
1754                strlen(path), STRLEN_CONST(".lpl")))
1755       {
1756          video_driver_texture_unload(&node->icon);
1757          video_driver_texture_unload(&node->content_icon);
1758       }
1759    }
1760 }
1761 
stripes_init_horizontal_list(stripes_handle_t * stripes)1762 static void stripes_init_horizontal_list(stripes_handle_t *stripes)
1763 {
1764    menu_displaylist_info_t info;
1765    settings_t *settings         = config_get_ptr();
1766 
1767    menu_displaylist_info_init(&info);
1768 
1769    info.list                    = &stripes->horizontal_list;
1770    info.path                    = strdup(
1771          settings->paths.directory_playlist);
1772 #if 0
1773    /* TODO/FIXME - will need to look what to do here */
1774    info.label                   = strdup(
1775          msg_hash_to_str(MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST));
1776    info.enum_idx                = MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST;
1777 #endif
1778    info.exts                    = strdup("lpl");
1779    info.type_default            = FILE_TYPE_PLAIN;
1780 
1781    if (!string_is_empty(info.path))
1782    {
1783       if (menu_displaylist_ctl(DISPLAYLIST_DATABASE_PLAYLISTS_HORIZONTAL, &info,
1784                settings))
1785       {
1786          size_t i;
1787          for (i = 0; i < stripes->horizontal_list.size; i++)
1788             stripes_node_allocate_userdata(stripes, (unsigned)i);
1789          menu_displaylist_process(&info);
1790       }
1791    }
1792 
1793    menu_displaylist_info_free(&info);
1794 }
1795 
stripes_toggle_horizontal_list(stripes_handle_t * stripes)1796 static void stripes_toggle_horizontal_list(stripes_handle_t *stripes)
1797 {
1798    unsigned i;
1799    size_t list_size = stripes_list_get_size(stripes, MENU_LIST_HORIZONTAL)
1800       + stripes->system_tab_end;
1801 
1802    for (i = 0; i <= list_size; i++)
1803    {
1804       stripes_node_t *node = stripes_get_node(stripes, i);
1805 
1806       if (!node)
1807          continue;
1808 
1809       node->alpha = 0;
1810       node->zoom  = stripes->categories_passive_zoom;
1811 
1812       if (i == stripes->categories_active_idx)
1813       {
1814          node->alpha = stripes->categories_active_alpha;
1815          node->zoom  = stripes->categories_active_zoom;
1816       }
1817       else if (stripes->depth <= 1)
1818          node->alpha = stripes->categories_passive_alpha;
1819    }
1820 }
1821 
stripes_context_reset_horizontal_list(stripes_handle_t * stripes)1822 static void stripes_context_reset_horizontal_list(
1823       stripes_handle_t *stripes)
1824 {
1825    unsigned i;
1826    int depth; /* keep this integer */
1827    size_t list_size                =
1828       stripes_list_get_size(stripes, MENU_LIST_HORIZONTAL);
1829 
1830    stripes->categories_x_pos           =
1831       stripes->categories_passive_width *
1832       -(float)stripes->categories_selection_ptr;
1833 
1834    depth                           = (stripes->depth > 1) ? 2 : 1;
1835    stripes->x                          = stripes->icon_size * -(depth*2-2);
1836 
1837    for (i = 0; i < list_size; i++)
1838    {
1839       const char *path                          = NULL;
1840       stripes_node_t *node                      =
1841          stripes_get_userdata_from_horizontal_list(stripes, i);
1842 
1843       if (!node)
1844          if (!(node = stripes_node_allocate_userdata(stripes, i)))
1845             continue;
1846 
1847       if (!(path = stripes->horizontal_list.list[i].path))
1848          continue;
1849       if (string_ends_with_size(path, ".lpl",
1850                strlen(path), STRLEN_CONST(".lpl")))
1851       {
1852          struct texture_image ti;
1853          char sysname[256];
1854          char iconpath[PATH_MAX_LENGTH];
1855          char texturepath[PATH_MAX_LENGTH];
1856          char content_texturepath[PATH_MAX_LENGTH];
1857 
1858          iconpath[0]    = sysname[0] =
1859          texturepath[0] = content_texturepath[0] = '\0';
1860 
1861          fill_pathname_base_noext(sysname, path, sizeof(sysname));
1862 
1863          fill_pathname_application_special(iconpath, sizeof(iconpath),
1864                APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_ICONS);
1865 
1866          fill_pathname_join_concat(texturepath, iconpath, sysname,
1867                ".png", sizeof(texturepath));
1868 
1869          ti.width         = 0;
1870          ti.height        = 0;
1871          ti.pixels        = NULL;
1872          ti.supports_rgba = video_driver_supports_rgba();
1873 
1874          if (image_texture_load(&ti, texturepath))
1875          {
1876             if (ti.pixels)
1877             {
1878                video_driver_texture_unload(&node->icon);
1879                video_driver_texture_load(&ti,
1880                      TEXTURE_FILTER_MIPMAP_LINEAR, &node->icon);
1881             }
1882 
1883             image_texture_free(&ti);
1884          }
1885 
1886          strlcat(iconpath, sysname, sizeof(iconpath));
1887          fill_pathname_join_delim(content_texturepath, iconpath,
1888                "content.png", '-', sizeof(content_texturepath));
1889 
1890          if (image_texture_load(&ti, content_texturepath))
1891          {
1892             if (ti.pixels)
1893             {
1894                video_driver_texture_unload(&node->content_icon);
1895                video_driver_texture_load(&ti,
1896                      TEXTURE_FILTER_MIPMAP_LINEAR, &node->content_icon);
1897             }
1898 
1899             image_texture_free(&ti);
1900          }
1901       }
1902    }
1903 
1904    stripes_toggle_horizontal_list(stripes);
1905 }
1906 
stripes_refresh_horizontal_list(stripes_handle_t * stripes)1907 static void stripes_refresh_horizontal_list(stripes_handle_t *stripes)
1908 {
1909    stripes_context_destroy_horizontal_list(stripes);
1910    stripes_free_list_nodes(stripes->horizontal_list, false);
1911    file_list_deinitialize(&stripes->horizontal_list);
1912 
1913    menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
1914 
1915    stripes_init_horizontal_list(stripes);
1916 
1917    stripes_context_reset_horizontal_list(stripes);
1918 }
1919 
stripes_environ(enum menu_environ_cb type,void * data,void * userdata)1920 static int stripes_environ(enum menu_environ_cb type, void *data, void *userdata)
1921 {
1922    stripes_handle_t *stripes        = (stripes_handle_t*)userdata;
1923 
1924    switch (type)
1925    {
1926       case MENU_ENVIRON_ENABLE_MOUSE_CURSOR:
1927          if (!stripes)
1928             return -1;
1929          stripes->mouse_show = true;
1930          break;
1931       case MENU_ENVIRON_DISABLE_MOUSE_CURSOR:
1932          if (!stripes)
1933             return -1;
1934          stripes->mouse_show = false;
1935          break;
1936       case MENU_ENVIRON_RESET_HORIZONTAL_LIST:
1937          if (!stripes)
1938             return -1;
1939 
1940          stripes_refresh_horizontal_list(stripes);
1941          break;
1942       default:
1943          return -1;
1944    }
1945 
1946    return 0;
1947 }
1948 
stripes_list_open(stripes_handle_t * stripes)1949 static void stripes_list_open(stripes_handle_t *stripes)
1950 {
1951    gfx_animation_ctx_entry_t entry;
1952 
1953    int                    dir = 0;
1954    file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
1955    size_t selection           = menu_navigation_get_selection();
1956 
1957    stripes->depth = (int)stripes_list_get_size(stripes, MENU_LIST_PLAIN);
1958 
1959    if (stripes->depth > stripes->old_depth)
1960       dir = 1;
1961    else if (stripes->depth < stripes->old_depth)
1962       dir = -1;
1963 
1964    stripes_list_open_horizontal_list(stripes);
1965 
1966    stripes_list_open_old(stripes,
1967          &stripes->selection_buf_old,
1968          dir, stripes->selection_ptr_old);
1969    stripes_list_open_new(stripes, selection_buf,
1970          dir, selection);
1971 
1972    entry.duration     = STRIPES_DELAY;
1973    entry.target_value = stripes->icon_size * -(stripes->depth*2-2);
1974    entry.subject      = &stripes->x;
1975    entry.easing_enum  = EASING_OUT_QUAD;
1976    /* TODO/FIXME - integer conversion resulted in change of sign */
1977    entry.tag          = -1;
1978    entry.cb           = NULL;
1979 
1980    switch (stripes->depth)
1981    {
1982       case 1:
1983          gfx_animation_push(&entry);
1984 
1985          entry.target_value = 0;
1986          entry.subject      = &stripes->textures_arrow_alpha;
1987 
1988          gfx_animation_push(&entry);
1989          break;
1990       case 2:
1991          gfx_animation_push(&entry);
1992 
1993          entry.target_value = 1;
1994          entry.subject      = &stripes->textures_arrow_alpha;
1995 
1996          gfx_animation_push(&entry);
1997          break;
1998    }
1999 
2000    stripes->old_depth = stripes->depth;
2001 }
2002 
stripes_populate_entries(void * data,const char * path,const char * label,unsigned k)2003 static void stripes_populate_entries(void *data,
2004       const char *path,
2005       const char *label, unsigned k)
2006 {
2007    stripes_handle_t *stripes = (stripes_handle_t*)data;
2008 
2009    if (!stripes)
2010       return;
2011 
2012    if (menu_driver_ctl(RARCH_MENU_CTL_IS_PREVENT_POPULATE, NULL))
2013    {
2014       stripes_selection_pointer_changed(stripes, false);
2015       menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL);
2016       if (!string_is_equal(stripes_thumbnails_ident('R'),
2017                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
2018          stripes_update_thumbnail_image(stripes);
2019       stripes_update_savestate_thumbnail_image(stripes);
2020       if (!string_is_equal(stripes_thumbnails_ident('L'),
2021                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
2022          stripes_update_thumbnail_image(stripes);
2023       return;
2024    }
2025 
2026    stripes_set_title(stripes);
2027 
2028    if (stripes->categories_selection_ptr != stripes->categories_active_idx_old)
2029       stripes_list_switch(stripes);
2030    else
2031       stripes_list_open(stripes);
2032 }
2033 
stripes_icon_get_id(stripes_handle_t * stripes,stripes_node_t * core_node,stripes_node_t * node,enum msg_hash_enums enum_idx,unsigned type,bool active)2034 static uintptr_t stripes_icon_get_id(stripes_handle_t *stripes,
2035       stripes_node_t *core_node, stripes_node_t *node,
2036       enum msg_hash_enums enum_idx, unsigned type, bool active)
2037 {
2038    switch (enum_idx)
2039    {
2040       case MENU_ENUM_LABEL_CORE_OPTIONS:
2041       case MENU_ENUM_LABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE:
2042          return stripes->textures.list[STRIPES_TEXTURE_CORE_OPTIONS];
2043       case MENU_ENUM_LABEL_CORE_OPTION_OVERRIDE_LIST:
2044          return stripes->textures.list[STRIPES_TEXTURE_SETTING];
2045       case MENU_ENUM_LABEL_ADD_TO_FAVORITES:
2046       case MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST:
2047          return stripes->textures.list[STRIPES_TEXTURE_ADD_FAVORITE];
2048       case MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION:
2049       case MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES:
2050          return stripes->textures.list[STRIPES_TEXTURE_RENAME];
2051       case MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS:
2052          return stripes->textures.list[STRIPES_TEXTURE_INPUT_REMAPPING_OPTIONS];
2053       case MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS:
2054          return stripes->textures.list[STRIPES_TEXTURE_CHEAT_OPTIONS];
2055       case MENU_ENUM_LABEL_DISK_OPTIONS:
2056          return stripes->textures.list[STRIPES_TEXTURE_DISK_OPTIONS];
2057       case MENU_ENUM_LABEL_SHADER_OPTIONS:
2058          return stripes->textures.list[STRIPES_TEXTURE_SHADER_OPTIONS];
2059       case MENU_ENUM_LABEL_ACHIEVEMENT_LIST:
2060          return stripes->textures.list[STRIPES_TEXTURE_ACHIEVEMENT_LIST];
2061       case MENU_ENUM_LABEL_ACHIEVEMENT_LIST_HARDCORE:
2062          return stripes->textures.list[STRIPES_TEXTURE_ACHIEVEMENT_LIST];
2063       case MENU_ENUM_LABEL_SAVE_STATE:
2064          return stripes->textures.list[STRIPES_TEXTURE_SAVESTATE];
2065       case MENU_ENUM_LABEL_LOAD_STATE:
2066          return stripes->textures.list[STRIPES_TEXTURE_LOADSTATE];
2067       case MENU_ENUM_LABEL_PARENT_DIRECTORY:
2068       case MENU_ENUM_LABEL_UNDO_LOAD_STATE:
2069       case MENU_ENUM_LABEL_UNDO_SAVE_STATE:
2070          return stripes->textures.list[STRIPES_TEXTURE_UNDO];
2071       case MENU_ENUM_LABEL_TAKE_SCREENSHOT:
2072          return stripes->textures.list[STRIPES_TEXTURE_SCREENSHOT];
2073       case MENU_ENUM_LABEL_DELETE_ENTRY:
2074          return stripes->textures.list[STRIPES_TEXTURE_CLOSE];
2075       case MENU_ENUM_LABEL_RESTART_CONTENT:
2076          return stripes->textures.list[STRIPES_TEXTURE_RELOAD];
2077       case MENU_ENUM_LABEL_RENAME_ENTRY:
2078          return stripes->textures.list[STRIPES_TEXTURE_RENAME];
2079       case MENU_ENUM_LABEL_RESUME_CONTENT:
2080          return stripes->textures.list[STRIPES_TEXTURE_RESUME];
2081       case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE:
2082       case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME:
2083          return stripes->textures.list[STRIPES_TEXTURE_SAVESTATE];
2084       case MENU_ENUM_LABEL_FAVORITES:
2085       case MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST:
2086          return stripes->textures.list[STRIPES_TEXTURE_FOLDER];
2087       case MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR:
2088          return stripes->textures.list[STRIPES_TEXTURE_RDB];
2089       default:
2090          break;
2091    }
2092 
2093    switch(type)
2094    {
2095       case FILE_TYPE_DIRECTORY:
2096          return stripes->textures.list[STRIPES_TEXTURE_FOLDER];
2097       case FILE_TYPE_PLAIN:
2098       case FILE_TYPE_IN_CARCHIVE:
2099          return stripes->textures.list[STRIPES_TEXTURE_FILE];
2100       case FILE_TYPE_RPL_ENTRY:
2101          if (core_node)
2102             return core_node->content_icon;
2103 
2104          switch (stripes_get_system_tab(stripes,
2105                   (unsigned)stripes->categories_selection_ptr))
2106          {
2107             case STRIPES_SYSTEM_TAB_FAVORITES:
2108                return stripes->textures.list[STRIPES_TEXTURE_FAVORITE];
2109             case STRIPES_SYSTEM_TAB_MUSIC:
2110                return stripes->textures.list[STRIPES_TEXTURE_MUSIC];
2111 #ifdef HAVE_IMAGEVIEWER
2112             case STRIPES_SYSTEM_TAB_IMAGES:
2113                return stripes->textures.list[STRIPES_TEXTURE_IMAGE];
2114 #endif
2115 #ifdef HAVE_FFMPEG
2116             case STRIPES_SYSTEM_TAB_VIDEO:
2117                return stripes->textures.list[STRIPES_TEXTURE_MOVIE];
2118 #endif
2119             default:
2120                break;
2121          }
2122          return stripes->textures.list[STRIPES_TEXTURE_FILE];
2123       case FILE_TYPE_CARCHIVE:
2124          return stripes->textures.list[STRIPES_TEXTURE_ZIP];
2125       case FILE_TYPE_MUSIC:
2126          return stripes->textures.list[STRIPES_TEXTURE_MUSIC];
2127       case FILE_TYPE_IMAGE:
2128       case FILE_TYPE_IMAGEVIEWER:
2129          return stripes->textures.list[STRIPES_TEXTURE_IMAGE];
2130       case FILE_TYPE_MOVIE:
2131          return stripes->textures.list[STRIPES_TEXTURE_MOVIE];
2132       case FILE_TYPE_CORE:
2133       case FILE_TYPE_DIRECT_LOAD:
2134          return stripes->textures.list[STRIPES_TEXTURE_CORE];
2135       case FILE_TYPE_RDB:
2136          return stripes->textures.list[STRIPES_TEXTURE_RDB];
2137       case FILE_TYPE_CURSOR:
2138          return stripes->textures.list[STRIPES_TEXTURE_CURSOR];
2139       case FILE_TYPE_PLAYLIST_ENTRY:
2140       case MENU_SETTING_ACTION_RUN:
2141          return stripes->textures.list[STRIPES_TEXTURE_RUN];
2142       case MENU_SETTING_ACTION_CLOSE:
2143       case MENU_SETTING_ACTION_CLOSE_HORIZONTAL:
2144          return stripes->textures.list[STRIPES_TEXTURE_CLOSE];
2145       case MENU_SETTING_ACTION_SAVESTATE:
2146          return stripes->textures.list[STRIPES_TEXTURE_SAVESTATE];
2147       case MENU_SETTING_ACTION_LOADSTATE:
2148          return stripes->textures.list[STRIPES_TEXTURE_LOADSTATE];
2149       case FILE_TYPE_RDB_ENTRY:
2150          return stripes->textures.list[STRIPES_TEXTURE_CORE_INFO];
2151       case MENU_SETTING_ACTION_CORE_OPTIONS:
2152       case MENU_ENUM_LABEL_SET_CORE_ASSOCIATION:
2153          return stripes->textures.list[STRIPES_TEXTURE_CORE_OPTIONS];
2154       case MENU_SETTING_ACTION_CORE_INPUT_REMAPPING_OPTIONS:
2155          return stripes->textures.list[STRIPES_TEXTURE_INPUT_REMAPPING_OPTIONS];
2156       case MENU_SETTING_ACTION_CORE_CHEAT_OPTIONS:
2157          return stripes->textures.list[STRIPES_TEXTURE_CHEAT_OPTIONS];
2158       case MENU_SETTING_ACTION_CORE_DISK_OPTIONS:
2159          return stripes->textures.list[STRIPES_TEXTURE_DISK_OPTIONS];
2160       case MENU_SETTING_ACTION_CORE_SHADER_OPTIONS:
2161          return stripes->textures.list[STRIPES_TEXTURE_SHADER_OPTIONS];
2162       case MENU_SETTING_ACTION_SCREENSHOT:
2163          return stripes->textures.list[STRIPES_TEXTURE_SCREENSHOT];
2164       case MENU_SETTING_ACTION_DELETE_ENTRY:
2165          return stripes->textures.list[STRIPES_TEXTURE_CLOSE];
2166       case MENU_SETTING_ACTION_RESET:
2167          return stripes->textures.list[STRIPES_TEXTURE_RELOAD];
2168       case MENU_SETTING_ACTION:
2169          if (stripes->depth == 3)
2170             return stripes->textures.list[STRIPES_TEXTURE_SUBSETTING];
2171          return stripes->textures.list[STRIPES_TEXTURE_SETTING];
2172       case MENU_SETTING_GROUP:
2173          return stripes->textures.list[STRIPES_TEXTURE_SETTING];
2174       case MENU_INFO_MESSAGE:
2175          return stripes->textures.list[STRIPES_TEXTURE_CORE_INFO];
2176       case MENU_BLUETOOTH:
2177          return stripes->textures.list[STRIPES_TEXTURE_BLUETOOTH];
2178       case MENU_WIFI:
2179          return stripes->textures.list[STRIPES_TEXTURE_WIFI];
2180 #ifdef HAVE_NETWORKING
2181       case MENU_ROOM:
2182          return stripes->textures.list[STRIPES_TEXTURE_ROOM];
2183 #if 0
2184       /* stub these out until we have the icons */
2185       case MENU_ROOM_LAN:
2186          return stripes->textures.list[STRIPES_TEXTURE_ROOM_LAN];
2187       case MENU_ROOM_MITM:
2188          return stripes->textures.list[STRIPES_TEXTURE_ROOM_MITM];
2189 #endif
2190 #endif
2191    }
2192 
2193 #ifdef HAVE_CHEEVOS
2194    if (
2195          (type >= MENU_SETTINGS_CHEEVOS_START) &&
2196          (type < MENU_SETTINGS_NETPLAY_ROOMS_START)
2197       )
2198    {
2199       int index = type - MENU_SETTINGS_CHEEVOS_START;
2200       uintptr_t badge_texture = cheevos_get_menu_badge_texture(index);
2201       if (badge_texture)
2202          return badge_texture;
2203       /* Should be replaced with placeholder badge icon. */
2204       return stripes->textures.list[STRIPES_TEXTURE_SUBSETTING];
2205    }
2206 #endif
2207 
2208    return stripes->textures.list[STRIPES_TEXTURE_SUBSETTING];
2209 }
2210 
stripes_calculate_visible_range(const stripes_handle_t * stripes,unsigned height,size_t list_size,unsigned current,unsigned * first,unsigned * last)2211 static void stripes_calculate_visible_range(const stripes_handle_t *stripes,
2212       unsigned height, size_t list_size, unsigned current,
2213       unsigned *first, unsigned *last)
2214 {
2215    unsigned j;
2216    float    base_y = stripes->margins_screen_top;
2217 
2218    *first = 0;
2219    *last  = list_size ? list_size - 1 : 0;
2220 
2221    if (current)
2222    {
2223       for (j = current; j-- > 0; )
2224       {
2225          float bottom = stripes_item_y(stripes, j, current)
2226             + base_y + stripes->icon_size;
2227 
2228          if (bottom < 0)
2229             break;
2230 
2231          *first = j;
2232       }
2233    }
2234 
2235    for (j = current+1; j < list_size; j++)
2236    {
2237       float top = stripes_item_y(stripes, j, current) + base_y;
2238 
2239       if (top > height)
2240          break;
2241 
2242       *last = j;
2243    }
2244 }
2245 
stripes_draw_item(void * userdata,unsigned video_width,unsigned video_height,bool xmb_shadows_enable,menu_entry_t * entry,math_matrix_4x4 * mymat,stripes_handle_t * stripes,stripes_node_t * core_node,file_list_t * list,float * color,const char * thumb_ident,const char * left_thumb_ident,size_t i,size_t current,unsigned width,unsigned height)2246 static int stripes_draw_item(
2247       void *userdata,
2248       unsigned video_width,
2249       unsigned video_height,
2250       bool xmb_shadows_enable,
2251       menu_entry_t *entry,
2252       math_matrix_4x4 *mymat,
2253       stripes_handle_t *stripes,
2254       stripes_node_t *core_node,
2255       file_list_t *list,
2256       float *color,
2257       const char *thumb_ident,
2258       const char *left_thumb_ident,
2259       size_t i,
2260       size_t current,
2261       unsigned width,
2262       unsigned height
2263       )
2264 {
2265    float icon_x, icon_y, label_offset;
2266    gfx_animation_ctx_ticker_t ticker;
2267    char tmp[255];
2268    const char *ticker_str            = NULL;
2269    unsigned entry_type               = 0;
2270    const float half_size             = stripes->icon_size / 2.0f;
2271    uintptr_t texture_switch          = 0;
2272    bool do_draw_text                 = false;
2273    unsigned ticker_limit             = 35 * stripes_scale_mod[0];
2274    stripes_node_t *   node               = (stripes_node_t*)
2275       file_list_get_userdata_at_offset(list, i);
2276    settings_t *settings              = config_get_ptr();
2277    gfx_animation_t *p_anim           = anim_get_ptr();
2278 
2279    /* Initial ticker configuration */
2280    ticker.type_enum = settings->uints.menu_ticker_type;
2281    ticker.spacer = NULL;
2282 
2283    if (!node)
2284       goto iterate;
2285 
2286    tmp[0] = '\0';
2287 
2288    icon_y = stripes->margins_screen_top + node->y + half_size;
2289 
2290    if (icon_y < half_size)
2291       goto iterate;
2292 
2293    if (icon_y > height + stripes->icon_size)
2294       goto end;
2295 
2296    icon_x = node->x + stripes->margins_screen_left +
2297       stripes->icon_spacing_horizontal - half_size;
2298 
2299    if (icon_x < -half_size || icon_x > width)
2300       goto iterate;
2301 
2302    entry_type = entry.type;
2303 
2304    if (entry_type == FILE_TYPE_CONTENTLIST_ENTRY)
2305    {
2306       char entry_path[PATH_MAX_LENGTH];
2307 
2308       entry_path[0] = '\0';
2309       strlcpy(entry_path, entry->path, sizeof(entry_path));
2310 
2311       fill_short_pathname_representation(entry_path, entry_path,
2312             sizeof(entry_path));
2313 
2314       if (!string_is_empty(entry_path))
2315       {
2316          if (!string_is_empty(entry->path))
2317             free(entry->path);
2318          entry->path = strdup(entry_path);
2319       }
2320    }
2321 
2322    if (string_is_equal(entry->value,
2323             msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) ||
2324          (string_is_equal(entry->value,
2325                           msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))))
2326    {
2327       if (stripes->textures.list[STRIPES_TEXTURE_SWITCH_OFF])
2328          texture_switch = stripes->textures.list[STRIPES_TEXTURE_SWITCH_OFF];
2329       else
2330          do_draw_text = true;
2331    }
2332    else if (string_is_equal(entry->value,
2333             msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) ||
2334          (string_is_equal(entry->value,
2335                           msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON))))
2336    {
2337       if (stripes->textures.list[STRIPES_TEXTURE_SWITCH_ON])
2338          texture_switch = stripes->textures.list[STRIPES_TEXTURE_SWITCH_ON];
2339       else
2340          do_draw_text = true;
2341    }
2342    else
2343    {
2344       if (!string_is_empty(entry->value))
2345       {
2346          if (
2347                string_is_equal(entry->value, "...")     ||
2348                string_is_equal(entry->value, "(COMP)")  ||
2349                string_is_equal(entry->value, "(CORE)")  ||
2350                string_is_equal(entry->value, "(MOVIE)") ||
2351                string_is_equal(entry->value, "(MUSIC)") ||
2352                string_is_equal(entry->value, "(DIR)")   ||
2353                string_is_equal(entry->value, "(RDB)")   ||
2354                string_is_equal(entry->value, "(CURSOR)")||
2355                string_is_equal(entry->value, "(CFILE)") ||
2356                string_is_equal(entry->value, "(FILE)")  ||
2357                string_is_equal(entry->value, "(IMAGE)")
2358             )
2359          {
2360          }
2361          else
2362                do_draw_text = true;
2363       }
2364       else
2365          do_draw_text = true;
2366 
2367    }
2368 
2369    if (string_is_empty(entry->value))
2370    {
2371       if (stripes->savestate_thumbnail ||
2372             (!string_is_equal
2373              (thumb_ident,
2374               msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))
2375              && stripes->thumbnail) ||
2376              (!string_is_equal
2377              (left_thumb_ident,
2378               msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))
2379              && stripes->left_thumbnail
2380              && settings->bools.menu_xmb_vertical_thumbnails)
2381          )
2382          ticker_limit = 40 * stripes_scale_mod[1];
2383       else
2384          ticker_limit = 70 * stripes_scale_mod[2];
2385    }
2386 
2387    if (!string_is_empty(entry->path))
2388    {
2389       if (!string_is_empty(entry.rich_label))
2390          ticker_str          = entry.rich_label;
2391       else
2392          ticker_str          = entry.path;
2393    }
2394 
2395    ticker.s        = tmp;
2396    ticker.len      = ticker_limit;
2397    ticker.idx      = p_anim->ticker_idx;
2398    ticker.str      = ticker_str;
2399    ticker.selected = (i == current);
2400 
2401    if (ticker.str)
2402       gfx_animation_ticker(&ticker);
2403 
2404    label_offset = stripes->margins_label_top;
2405    if (i == current && width > 320 && height > 240
2406          && !string_is_empty(entry->sublabel))
2407    {
2408       char entry_sublabel[MENU_SUBLABEL_MAX_LENGTH] = {0};
2409 
2410       label_offset      = - stripes->margins_label_top;
2411 
2412       (stripes->word_wrap)(entry_sublabel, sizeof(entry_sublabel),
2413             entry->sublabel, 50 * stripes_scale_mod[3], 100, 0);
2414 
2415       stripes_draw_text(xmb_shadows_enable, stripes, entry_sublabel,
2416             node->x + stripes->margins_screen_left +
2417             stripes->icon_spacing_horizontal + stripes->margins_label_left,
2418             stripes->margins_screen_top + node->y + stripes->margins_label_top*3.5,
2419             1, node->label_alpha, TEXT_ALIGN_LEFT,
2420             width, height, stripes->font2);
2421    }
2422 
2423    stripes_draw_text(xmb_shadows_enable, stripes, tmp,
2424          node->x + stripes->margins_screen_left +
2425          stripes->icon_spacing_horizontal + stripes->margins_label_left,
2426          stripes->margins_screen_top + node->y + label_offset,
2427          1, node->label_alpha, TEXT_ALIGN_LEFT,
2428          width, height, stripes->font);
2429 
2430    tmp[0]          = '\0';
2431 
2432    ticker.s        = tmp;
2433    ticker.len      = 35 * stripes_scale_mod[7];
2434    ticker.idx      = p_anim->ticker_idx;
2435    ticker.selected = (i == current);
2436 
2437    if (!string_is_empty(entry->value))
2438    {
2439       ticker.str   = entry->value;
2440       gfx_animation_ticker(&ticker);
2441    }
2442 
2443    if (do_draw_text)
2444       stripes_draw_text(xmb_shadows_enable, stripes, tmp,
2445             node->x +
2446             + stripes->margins_screen_left
2447             + stripes->icon_spacing_horizontal
2448             + stripes->margins_label_left
2449             + stripes->margins_setting_left,
2450             stripes->margins_screen_top + node->y + stripes->margins_label_top,
2451             1,
2452             node->label_alpha,
2453             TEXT_ALIGN_LEFT,
2454             width, height, stripes->font);
2455 
2456    gfx_display_set_alpha(color, MIN(node->alpha, stripes->alpha));
2457 
2458    if (color[3] != 0)
2459    {
2460       math_matrix_4x4 mymat_tmp;
2461       gfx_display_ctx_rotate_draw_t rotate_draw;
2462       uintptr_t texture        = stripes_icon_get_id(stripes, core_node, node,
2463             entry->enum_idx, entry_type, (i == current));
2464       float x                  = icon_x;
2465       float y                  = icon_y;
2466       float rotation           = 0;
2467       float scale_factor       = node->zoom;
2468 
2469       rotate_draw.matrix       = &mymat_tmp;
2470       rotate_draw.rotation     = rotation;
2471       rotate_draw.scale_x      = scale_factor;
2472       rotate_draw.scale_y      = scale_factor;
2473       rotate_draw.scale_z      = 1;
2474       rotate_draw.scale_enable = true;
2475 
2476       gfx_display_rotate_z(p_disp, &rotate_draw, userdata);
2477 
2478       stripes_draw_icon(
2479             userdata,
2480             video_width,
2481             video_height,
2482             xmb_shadows_enable,
2483             stripes->icon_size,
2484             &mymat_tmp,
2485             texture,
2486             x,
2487             y,
2488             width,
2489             height,
2490             1.0,
2491             rotation,
2492             scale_factor,
2493             &color[0],
2494             stripes->shadow_offset);
2495    }
2496 
2497    gfx_display_set_alpha(color, MIN(node->alpha, stripes->alpha));
2498 
2499    if (texture_switch != 0 && color[3] != 0)
2500       stripes_draw_icon(
2501             userdata,
2502             video_width,
2503             video_height,
2504             xmb_shadows_enable,
2505             stripes->icon_size,
2506             mymat,
2507             texture_switch,
2508             node->x + stripes->margins_screen_left
2509             + stripes->icon_spacing_horizontal
2510             + stripes->icon_size / 2.0 + stripes->margins_setting_left,
2511             stripes->margins_screen_top + node->y + stripes->icon_size / 2.0,
2512             width, height,
2513             node->alpha,
2514             0,
2515             1,
2516             &color[0],
2517             stripes->shadow_offset);
2518 
2519 iterate:
2520    return 0;
2521 
2522 end:
2523    return -1;
2524 }
2525 
stripes_draw_items(void * userdata,unsigned video_width,unsigned video_height,bool xmb_shadows_enable,stripes_handle_t * stripes,file_list_t * list,size_t current,size_t cat_selection_ptr,float * color,unsigned width,unsigned height)2526 static void stripes_draw_items(
2527       void *userdata,
2528       unsigned video_width,
2529       unsigned video_height,
2530       bool xmb_shadows_enable,
2531       stripes_handle_t *stripes,
2532       file_list_t *list,
2533       size_t current, size_t cat_selection_ptr, float *color,
2534       unsigned width, unsigned height)
2535 {
2536    size_t i;
2537    unsigned first, last;
2538    math_matrix_4x4 mymat;
2539    gfx_display_ctx_rotate_draw_t rotate_draw;
2540    stripes_node_t *core_node    = NULL;
2541    size_t end                   = 0;
2542    const char *thumb_ident      = stripes_thumbnails_ident('R');
2543    const char *left_thumb_ident = stripes_thumbnails_ident('L');
2544    gfx_display_t            *p_disp  = disp_get_ptr();
2545    gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
2546 
2547    if (!list || !list->size || !stripes)
2548       return;
2549 
2550    if (cat_selection_ptr > stripes->system_tab_end)
2551       core_node = stripes_get_userdata_from_horizontal_list(
2552             stripes, (unsigned)(cat_selection_ptr - (stripes->system_tab_end + 1)));
2553 
2554    end                      = list ? list->size : NULL;
2555 
2556    rotate_draw.matrix       = &mymat;
2557    rotate_draw.rotation     = 0;
2558    rotate_draw.scale_x      = 1;
2559    rotate_draw.scale_y      = 1;
2560    rotate_draw.scale_z      = 1;
2561    rotate_draw.scale_enable = true;
2562 
2563    gfx_display_rotate_z(p_disp, &rotate_draw, userdata);
2564 
2565    menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i);
2566 
2567    if (list == &stripes->selection_buf_old)
2568    {
2569       stripes_node_t *node = (stripes_node_t*)
2570             file_list_get_userdata_at_offset(list, current);
2571 
2572       if (node && (uint8_t)(255 * node->alpha) == 0)
2573          return;
2574 
2575       i = 0;
2576    }
2577 
2578    first = i;
2579    last  = end - 1;
2580 
2581    stripes_calculate_visible_range(stripes, height, end, current, &first, &last);
2582 
2583    if (dispctx && dispctx->blend_begin)
2584       dispctx->blend_begin(userdata);
2585 
2586    for (i = first; i <= last; i++)
2587    {
2588       int ret;
2589       menu_entry_t entry;
2590       MENU_ENTRY_INIT(entry);
2591       menu_entry_get(&entry, 0, i, list, true);
2592       ret = stripes_draw_item(
2593             userdata,
2594             video_width,
2595             video_height,
2596             xmb_shadows_enable,
2597             &entry,
2598             &mymat,
2599             stripes, core_node,
2600             list, color, thumb_ident, left_thumb_ident,
2601             i, current,
2602             width, height);
2603       if (ret == -1)
2604          break;
2605    }
2606 
2607    if (dispctx && dispctx->blend_end)
2608       dispctx->blend_end(userdata);
2609 }
2610 
stripes_render(void * data,unsigned width,unsigned height,bool is_idle)2611 static void stripes_render(void *data,
2612       unsigned width, unsigned height,
2613       bool is_idle)
2614 {
2615    size_t i;
2616    menu_input_pointer_t pointer;
2617    settings_t   *settings    = config_get_ptr();
2618    stripes_handle_t *stripes = (stripes_handle_t*)data;
2619    unsigned      end         = (unsigned)menu_entries_get_size();
2620    gfx_animation_t *p_anim   = anim_get_ptr();
2621 
2622    if (!stripes)
2623       return;
2624 
2625    menu_input_get_pointer_state(&pointer);
2626 
2627    if (pointer.type != MENU_POINTER_DISABLED)
2628    {
2629       size_t selection  = menu_navigation_get_selection();
2630       int16_t pointer_y = pointer.y;
2631       unsigned first = 0, last = end;
2632 
2633       pointer_y = (pointer.type == MENU_POINTER_MOUSE) ?
2634             pointer_y + (stripes->cursor_size/2) : pointer_y;
2635 
2636       if (height)
2637          stripes_calculate_visible_range(stripes, height,
2638                end, selection, &first, &last);
2639 
2640       for (i = first; i <= last; i++)
2641       {
2642          float item_y1     = stripes->margins_screen_top
2643             + stripes_item_y(stripes, (int)i, selection);
2644          float item_y2     = item_y1 + stripes->icon_size;
2645 
2646          if (pointer_y > item_y1 && pointer_y < item_y2)
2647             menu_input_set_pointer_selection(i);
2648       }
2649    }
2650 
2651    menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i);
2652 
2653    if (i >= end)
2654    {
2655       i = 0;
2656       menu_entries_ctl(MENU_ENTRIES_CTL_SET_START, &i);
2657    }
2658 
2659    GFX_ANIMATION_CLEAR_ACTIVE(p_anim);
2660 }
2661 
stripes_shader_pipeline_active(unsigned menu_shader_pipeline)2662 static bool stripes_shader_pipeline_active(unsigned menu_shader_pipeline)
2663 {
2664    if (string_is_not_equal(menu_driver_ident(), "stripes"))
2665       return false;
2666    if (menu_shader_pipeline == XMB_SHADER_PIPELINE_WALLPAPER)
2667       return false;
2668    return true;
2669 }
2670 
stripes_draw_bg(stripes_handle_t * stripes,void * userdata,unsigned video_width,unsigned video_height,unsigned width,unsigned height)2671 static void stripes_draw_bg(
2672       stripes_handle_t *stripes,
2673       void *userdata,
2674       unsigned video_width,
2675       unsigned video_height,
2676       unsigned width,
2677       unsigned height)
2678 {
2679    gfx_display_ctx_draw_t draw;
2680    struct video_coords coords;
2681    float rgb[3];
2682    HSLToRGB(0.0,0.5,0.5, &rgb[0]);
2683    float color[16] = {
2684       rgb[0], rgb[1], rgb[2], 1,
2685       rgb[0], rgb[1], rgb[2], 1,
2686       rgb[0], rgb[1], rgb[2], 1,
2687       rgb[0], rgb[1], rgb[2], 1,
2688    };
2689    gfx_display_t            *p_disp  = disp_get_ptr();
2690    gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
2691 
2692    coords.vertices      = 4;
2693    coords.vertex        = NULL;
2694    coords.tex_coord     = NULL;
2695    coords.lut_tex_coord = NULL;
2696    coords.color         = &color[0];
2697 
2698    draw.x           = 0;
2699    draw.y           = 0;
2700    draw.width       = width;
2701    draw.height      = height;
2702    draw.coords      = &coords;
2703    draw.matrix_data = NULL;
2704    draw.texture     = gfx_display_white_texture;
2705    draw.prim_type   = GFX_DISPLAY_PRIM_TRIANGLESTRIP;
2706    draw.pipeline_id = 0;
2707 
2708    if (dispctx)
2709    {
2710       if (dispctx->blend_begin)
2711          dispctx->blend_begin(userdata);
2712       if (dispctx->draw)
2713          if (draw.height > 0 && draw.width > 0)
2714             dispctx->draw(&draw, userdata, video_width, video_height);
2715       if (dispctx->blend_end)
2716          dispctx->blend_end(userdata);
2717    }
2718 }
2719 
stripes_draw_dark_layer(stripes_handle_t * stripes,void * userdata,unsigned video_width,unsigned video_height,unsigned width,unsigned height)2720 static void stripes_draw_dark_layer(
2721       stripes_handle_t *stripes,
2722       void *userdata,
2723       unsigned video_width,
2724       unsigned video_height,
2725       unsigned width,
2726       unsigned height)
2727 {
2728    gfx_display_ctx_draw_t draw;
2729    struct video_coords coords;
2730    float black[16] = {
2731       0, 0, 0, 1,
2732       0, 0, 0, 1,
2733       0, 0, 0, 1,
2734       0, 0, 0, 1,
2735    };
2736    gfx_display_t            *p_disp  = disp_get_ptr();
2737    gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
2738 
2739    gfx_display_set_alpha(black, MIN(stripes->alpha, 0.75));
2740 
2741    coords.vertices      = 4;
2742    coords.vertex        = NULL;
2743    coords.tex_coord     = NULL;
2744    coords.lut_tex_coord = NULL;
2745    coords.color         = &black[0];
2746 
2747    draw.x           = 0;
2748    draw.y           = 0;
2749    draw.width       = width;
2750    draw.height      = height;
2751    draw.coords      = &coords;
2752    draw.matrix_data = NULL;
2753    draw.texture     = gfx_display_white_texture;
2754    draw.prim_type   = GFX_DISPLAY_PRIM_TRIANGLESTRIP;
2755    draw.pipeline_id = 0;
2756 
2757    if (dispctx)
2758    {
2759       if (dispctx->blend_begin)
2760          dispctx->blend_begin(userdata);
2761       if (dispctx->draw)
2762          if (draw.height > 0 && draw.width > 0)
2763             dispctx->draw(&draw, userdata, video_width, video_height);
2764       if (dispctx->blend_end)
2765          dispctx->blend_end(userdata);
2766    }
2767 }
2768 
stripes_frame(void * data,video_frame_info_t * video_info)2769 static void stripes_frame(void *data, video_frame_info_t *video_info)
2770 {
2771    math_matrix_4x4 mymat;
2772    unsigned i;
2773    gfx_display_ctx_rotate_draw_t rotate_draw;
2774    char msg[1024];
2775    char title_msg[255];
2776    char title_truncated[255];
2777    size_t selection                        = 0;
2778    size_t percent_width                    = 0;
2779    const int min_thumb_size                = 50;
2780    bool render_background                  = false;
2781    file_list_t *selection_buf              = NULL;
2782    void *userdata                          = video_info->userdata;
2783    unsigned video_width                    = video_info->width;
2784    unsigned video_height                   = video_info->height;
2785    float xmb_alpha_factor                  = video_info->xmb_alpha_factor;
2786    bool xmb_shadows_enable                 = video_info->xmb_shadows_enable;
2787    bool video_fullscreen                   = video_info->fullscreen;
2788    bool mouse_grabbed                      = video_info->input_driver_grab_mouse_state;
2789    bool menu_mouse_enable                  = video_info->menu_mouse_enable;
2790    const float under_thumb_margin          = 0.96;
2791    float scale_factor                      = 0.0f;
2792    float pseudo_font_length                = 0.0f;
2793    float stack_width                       = 285;
2794    stripes_handle_t *stripes               = (stripes_handle_t*)data;
2795    settings_t *settings                    = config_get_ptr();
2796    gfx_display_t            *p_disp  = disp_get_ptr();
2797    gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
2798 
2799    if (!stripes)
2800       return;
2801 
2802    scale_factor                            = (settings->floats.menu_scale_factor * (float)video_width) / 1920.0f;
2803    pseudo_font_length                      = stripes->icon_spacing_horizontal * 4 - stripes->icon_size / 4;
2804 
2805    msg[0]             = '\0';
2806    title_msg[0]       = '\0';
2807    title_truncated[0] = '\0';
2808 
2809    font_driver_bind_block(stripes->font,  &stripes->raster_block);
2810    font_driver_bind_block(stripes->font2, &stripes->raster_block2);
2811 
2812    stripes->raster_block.carr.coords.vertices  = 0;
2813    stripes->raster_block2.carr.coords.vertices = 0;
2814 
2815    gfx_display_set_alpha(stripes_coord_black, MIN(
2816          (float)xmb_alpha_factor / 100, stripes->alpha));
2817    gfx_display_set_alpha(stripes_coord_white, stripes->alpha);
2818 
2819    stripes_draw_bg(
2820          stripes,
2821          userdata,
2822          video_width,
2823          video_height,
2824          video_width,
2825          video_height);
2826 
2827    selection = menu_navigation_get_selection();
2828 
2829    rotate_draw.matrix       = &mymat;
2830    rotate_draw.rotation     = 0;
2831    rotate_draw.scale_x      = 1;
2832    rotate_draw.scale_y      = 1;
2833    rotate_draw.scale_z      = 1;
2834    rotate_draw.scale_enable = true;
2835 
2836    gfx_display_rotate_z(p_disp, &rotate_draw, userdata);
2837    if (dispctx && dispctx->blend_begin)
2838       dispctx->blend_begin(userdata);
2839 
2840    /* Horizontal stripes */
2841    for (i = 0; i <= stripes_list_get_size(stripes, MENU_LIST_HORIZONTAL)
2842       + stripes->system_tab_end; i++)
2843    {
2844       float color[16];
2845       float rgb[3];
2846       stripes_node_t *node = stripes_get_node(stripes, i);
2847 
2848       if (!node)
2849          continue;
2850 
2851       HSLToRGB(0.07*(float)i,0.5,0.5, &rgb[0]) ;
2852       color[0]        = rgb[0];
2853       color[1]        = rgb[1];
2854       color[2]        = rgb[2];
2855       color[3]        = 0.55;
2856       color[4]        = rgb[0];
2857       color[5]        = rgb[1];
2858       color[6]        = rgb[2];
2859       color[7]        = 0.55;
2860       color[8]        = rgb[0];
2861       color[9]        = rgb[1];
2862       color[10]       = rgb[2];
2863       color[11]       = 0.55;
2864       color[12]       = rgb[0];
2865       color[13]       = rgb[1];
2866       color[14]       = rgb[2];
2867       color[15]       = 0.55;
2868 
2869       gfx_display_draw_polygon(
2870             p_disp,
2871             userdata,
2872             video_width,
2873             video_height,
2874             stripes->categories_x_pos + stack_width,
2875             0,
2876             stripes->categories_x_pos + stack_width + node->width,
2877             0,
2878             stripes->categories_x_pos + stack_width + stripes->categories_angle,
2879             video_height,
2880             stripes->categories_x_pos + stack_width + stripes->categories_angle + node->width,
2881             video_height,
2882             video_width, video_height,
2883             &color[0]);
2884 
2885       if (dispctx && dispctx->blend_begin)
2886          dispctx->blend_begin(userdata);
2887 
2888       stack_width += node->width;
2889    }
2890 
2891    stack_width = 285;
2892 
2893    /* Horizontal tab icons */
2894    for (i = 0; i <= stripes_list_get_size(stripes, MENU_LIST_HORIZONTAL)
2895       + stripes->system_tab_end; i++)
2896    {
2897       stripes_node_t *node = stripes_get_node(stripes, i);
2898 
2899       if (!node)
2900          continue;
2901 
2902       gfx_display_set_alpha(stripes_item_color, MIN(node->alpha, stripes->alpha));
2903 
2904       if (stripes_item_color[3] != 0)
2905       {
2906          gfx_display_ctx_rotate_draw_t rotate_draw;
2907          math_matrix_4x4 mymat;
2908          uintptr_t texture        = node->icon;
2909          float x                  = stripes->categories_x_pos + stack_width + node->x + node->width / 2.0
2910                                     - stripes->icon_size / 2.0;
2911          float y                  = node->y + stripes->icon_size / 2.0;
2912          float rotation           = 0;
2913          float scale_factor       = node->zoom;
2914 
2915          rotate_draw.matrix       = &mymat;
2916          rotate_draw.rotation     = rotation;
2917          rotate_draw.scale_x      = scale_factor;
2918          rotate_draw.scale_y      = scale_factor;
2919          rotate_draw.scale_z      = 1;
2920          rotate_draw.scale_enable = true;
2921 
2922          gfx_display_rotate_z(p_disp, &rotate_draw, userdata);
2923 
2924          stripes_draw_icon(
2925                userdata,
2926                video_width,
2927                video_height,
2928                xmb_shadows_enable,
2929                stripes->icon_size,
2930                &mymat,
2931                texture,
2932                x,
2933                y,
2934                video_width,
2935                video_height,
2936                1.0,
2937                rotation,
2938                scale_factor,
2939                &stripes_item_color[0],
2940                stripes->shadow_offset);
2941       }
2942 
2943       stack_width += node->width;
2944    }
2945 
2946    if (dispctx && dispctx->blend_end)
2947       dispctx->blend_end(userdata);
2948 
2949    /* Vertical icons */
2950 #if 0
2951    if (stripes)
2952       stripes_draw_items(
2953             userdata,
2954             video_width,
2955             video_height,
2956             xmb_shadows_enable,
2957             stripes,
2958             &stripes->selection_buf_old,
2959             stripes->selection_ptr_old,
2960             (stripes_list_get_size(stripes, MENU_LIST_PLAIN) > 1)
2961             ? stripes->categories_selection_ptr :
2962             stripes->categories_selection_ptr_old,
2963             &stripes_item_color[0],
2964             video_width,
2965             video_height);
2966 
2967    selection_buf = menu_entries_get_selection_buf_ptr(0);
2968 
2969    if (stripes)
2970       stripes_draw_items(
2971             userdata,
2972             video_width,
2973             video_height,
2974             xmb_shadows_enable,
2975             stripes,
2976             selection_buf,
2977             selection,
2978             stripes->categories_selection_ptr,
2979             &stripes_item_color[0],
2980             video_width,
2981             video_height);
2982 #endif
2983 
2984    font_driver_flush(video_width, video_height, stripes->font);
2985    font_driver_bind_block(stripes->font, NULL);
2986 
2987    font_driver_flush(video_width, video_height, stripes->font2);
2988    font_driver_bind_block(stripes->font2, NULL);
2989 
2990    if (menu_input_dialog_get_display_kb())
2991    {
2992       const char *str   = menu_input_dialog_get_buffer();
2993       const char *label = menu_input_dialog_get_label_buffer();
2994 
2995       snprintf(msg, sizeof(msg), "%s\n%s", label, str);
2996       render_background = true;
2997    }
2998 
2999    if (!string_is_empty(stripes->box_message))
3000    {
3001       strlcpy(msg, stripes->box_message,
3002             sizeof(msg));
3003       free(stripes->box_message);
3004       stripes->box_message  = NULL;
3005       render_background     = true;
3006    }
3007 
3008    if (render_background)
3009    {
3010       stripes_draw_dark_layer(stripes,
3011             userdata,
3012             video_width,
3013             video_height,
3014             video_width,
3015             video_height);
3016       stripes_render_messagebox_internal(
3017             stripes,
3018             userdata,
3019             video_width,
3020             video_height,
3021             msg);
3022    }
3023 
3024    /* Cursor image */
3025    if (stripes->mouse_show)
3026    {
3027       menu_input_pointer_t pointer;
3028       bool cursor_visible = (video_fullscreen || mouse_grabbed) &&
3029             menu_mouse_enable;
3030 
3031       menu_input_get_pointer_state(&pointer);
3032 
3033       gfx_display_set_alpha(stripes_coord_white, MIN(stripes->alpha, 1.00f));
3034 
3035       if (cursor_visible)
3036          gfx_display_draw_cursor(
3037                p_disp,
3038                userdata,
3039                video_width,
3040                video_height,
3041                cursor_visible,
3042                &stripes_coord_white[0],
3043                stripes->cursor_size,
3044                stripes->textures.list[STRIPES_TEXTURE_POINTER],
3045                pointer.x,
3046                pointer.y,
3047                video_width,
3048                video_height);
3049    }
3050 
3051    video_driver_set_viewport(video_width, video_height, false, true);
3052 }
3053 
stripes_layout_ps3(stripes_handle_t * stripes,int width,int height)3054 static void stripes_layout_ps3(stripes_handle_t *stripes, int width, int height)
3055 {
3056    unsigned new_font_size, new_header_height;
3057    gfx_display_t *p_disp         = disp_get_ptr();
3058    settings_t *settings          = config_get_ptr();
3059 
3060    float scale_factor            =
3061       (settings->floats.menu_scale_factor * width) / 1920.0f;
3062 
3063    stripes->above_subitem_offset     =   1.5;
3064    stripes->above_item_offset        =  -1.0;
3065    stripes->active_item_factor       =   3.0;
3066    stripes->under_item_offset        =   5.0;
3067 
3068    stripes->categories_active_zoom   = 1.0;
3069    stripes->categories_passive_zoom  = 0.25;
3070 
3071    stripes->categories_angle         = 400 * scale_factor;
3072 
3073    stripes->categories_active_y      = height / 2;
3074    stripes->categories_before_y      = 64 * scale_factor;
3075    stripes->categories_after_y       = height - 64 * scale_factor;
3076 
3077    stripes->categories_active_x      = stripes->categories_angle / 2;
3078    stripes->categories_before_x      = stripes->categories_angle - 22 * scale_factor;
3079    stripes->categories_after_x       = 22 * scale_factor;
3080 
3081    stripes->categories_passive_width = 128 * scale_factor;
3082    stripes->categories_active_width  = 1200 * scale_factor;
3083 
3084    stripes->items_active_zoom        = 1.0;
3085    stripes->items_passive_zoom       = 0.5;
3086 
3087    stripes->categories_active_alpha  = 1.0;
3088    stripes->categories_passive_alpha = 1.0;
3089    stripes->items_active_alpha       = 1.0;
3090    stripes->items_passive_alpha      = 0.85;
3091 
3092    stripes->shadow_offset            = 2.0;
3093 
3094    new_font_size                 = 32.0  * scale_factor;
3095    stripes->font2_size               = 24.0  * scale_factor;
3096    new_header_height             = 128.0 * scale_factor;
3097 
3098    stripes->thumbnail_width          = 1024.0 * scale_factor;
3099    stripes->left_thumbnail_width     = 1024.0 * scale_factor;
3100    stripes->savestate_thumbnail_width= 460.0 * scale_factor;
3101    stripes->cursor_size              = 64.0 * scale_factor;
3102 
3103    stripes->icon_spacing_horizontal  = 200.0 * scale_factor;
3104    stripes->icon_spacing_vertical    = 64.0 * scale_factor;
3105 
3106    stripes->margins_screen_top       = (256+32) * scale_factor;
3107    stripes->margins_screen_left      = 336.0 * scale_factor;
3108 
3109    stripes->margins_title_left       = 60 * scale_factor;
3110    stripes->margins_title_top        = 60 * scale_factor + new_font_size / 3;
3111    stripes->margins_title_bottom     = 60 * scale_factor - new_font_size / 3;
3112 
3113    stripes->margins_label_left       = 85.0 * scale_factor;
3114    stripes->margins_label_top        = new_font_size / 3.0;
3115 
3116    stripes->margins_setting_left     = 600.0 * scale_factor * stripes_scale_mod[6];
3117    stripes->margins_dialog           = 48 * scale_factor;
3118 
3119    stripes->margins_slice            = 16;
3120 
3121    stripes->icon_size                = 256.0 * scale_factor;
3122    stripes->font_size                = new_font_size;
3123 
3124 #ifdef STRIPES_DEBUG
3125    RARCH_LOG("[XMB] margin screen left: %.2f\n",  stripes->margins_screen_left);
3126    RARCH_LOG("[XMB] margin screen top:  %.2f\n",  stripes->margins_screen_top);
3127    RARCH_LOG("[XMB] margin title left:  %.2f\n",  stripes->margins_title_left);
3128    RARCH_LOG("[XMB] margin title top:   %.2f\n",  stripes->margins_title_top);
3129    RARCH_LOG("[XMB] margin title bott:  %.2f\n",  stripes->margins_title_bottom);
3130    RARCH_LOG("[XMB] margin label left:  %.2f\n",  stripes->margins_label_left);
3131    RARCH_LOG("[XMB] margin label top:   %.2f\n",  stripes->margins_label_top);
3132    RARCH_LOG("[XMB] margin sett left:   %.2f\n",  stripes->margins_setting_left);
3133    RARCH_LOG("[XMB] icon spacing hor:   %.2f\n",  stripes->icon_spacing_horizontal);
3134    RARCH_LOG("[XMB] icon spacing ver:   %.2f\n",  stripes->icon_spacing_vertical);
3135    RARCH_LOG("[XMB] icon size:          %.2f\n",  stripes->icon_size);
3136 #endif
3137 
3138    p_disp->header_height = new_header_height;
3139 }
3140 
stripes_layout_psp(stripes_handle_t * stripes,int width)3141 static void stripes_layout_psp(stripes_handle_t *stripes, int width)
3142 {
3143    unsigned new_font_size, new_header_height;
3144    gfx_display_t *p_disp         = disp_get_ptr();
3145    settings_t *settings          = config_get_ptr();
3146    float scale_factor            =
3147       ((settings->floats.menu_scale_factor * width) / 1920.0) * 1.5;
3148 #ifdef _3DS
3149    scale_factor                  =
3150       settings->floats.menu_scale_factor / 4.0;
3151 #endif
3152 
3153    stripes->above_subitem_offset     =  1.5;
3154    stripes->above_item_offset        = -1.0;
3155    stripes->active_item_factor       =  2.0;
3156    stripes->under_item_offset        =  3.0;
3157 
3158    stripes->categories_active_zoom   = 1.0;
3159    stripes->categories_passive_zoom  = 1.0;
3160    stripes->items_active_zoom        = 1.0;
3161    stripes->items_passive_zoom       = 1.0;
3162 
3163    stripes->categories_active_alpha  = 1.0;
3164    stripes->categories_passive_alpha = 0.85;
3165    stripes->items_active_alpha       = 1.0;
3166    stripes->items_passive_alpha      = 0.85;
3167 
3168    stripes->shadow_offset            = 1.0;
3169 
3170    new_font_size                 = 32.0  * scale_factor;
3171    stripes->font2_size               = 24.0  * scale_factor;
3172    new_header_height             = 128.0 * scale_factor;
3173    stripes->margins_screen_top       = (256+32) * scale_factor;
3174 
3175    stripes->thumbnail_width          = 460.0 * scale_factor;
3176    stripes->left_thumbnail_width     = 400.0 * scale_factor;
3177    stripes->savestate_thumbnail_width= 460.0 * scale_factor;
3178    stripes->cursor_size              = 64.0;
3179 
3180    stripes->icon_spacing_horizontal  = 250.0 * scale_factor;
3181    stripes->icon_spacing_vertical    = 108.0 * scale_factor;
3182 
3183    stripes->margins_screen_left      = 136.0 * scale_factor;
3184    stripes->margins_title_left       = 60 * scale_factor;
3185    stripes->margins_title_top        = 60 * scale_factor + new_font_size / 3;
3186    stripes->margins_title_bottom     = 60 * scale_factor - new_font_size / 3;
3187    stripes->margins_label_left       = 85.0 * scale_factor;
3188    stripes->margins_label_top        = new_font_size / 3.0;
3189    stripes->margins_setting_left     = 600.0 * scale_factor;
3190    stripes->margins_dialog           = 48 * scale_factor;
3191    stripes->margins_slice            = 16;
3192    stripes->icon_size                = 128.0 * scale_factor;
3193    stripes->font_size                = new_font_size;
3194 
3195 #ifdef STRIPES_DEBUG
3196    RARCH_LOG("[XMB] margin screen left: %.2f\n",  stripes->margins_screen_left);
3197    RARCH_LOG("[XMB] margin screen top:  %.2f\n",  stripes->margins_screen_top);
3198    RARCH_LOG("[XMB] margin title left:  %.2f\n",  stripes->margins_title_left);
3199    RARCH_LOG("[XMB] margin title top:   %.2f\n",  stripes->margins_title_top);
3200    RARCH_LOG("[XMB] margin title bott:  %.2f\n",  stripes->margins_title_bottom);
3201    RARCH_LOG("[XMB] margin label left:  %.2f\n",  stripes->margins_label_left);
3202    RARCH_LOG("[XMB] margin label top:   %.2f\n",  stripes->margins_label_top);
3203    RARCH_LOG("[XMB] margin sett left:   %.2f\n",  stripes->margins_setting_left);
3204    RARCH_LOG("[XMB] icon spacing hor:   %.2f\n",  stripes->icon_spacing_horizontal);
3205    RARCH_LOG("[XMB] icon spacing ver:   %.2f\n",  stripes->icon_spacing_vertical);
3206    RARCH_LOG("[XMB] icon size:          %.2f\n",  stripes->icon_size);
3207 #endif
3208 
3209    p_disp->header_height = new_header_height;
3210 }
3211 
stripes_layout(stripes_handle_t * stripes)3212 static void stripes_layout(stripes_handle_t *stripes)
3213 {
3214    unsigned width, height, i, current, end;
3215    file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
3216    size_t selection           = menu_navigation_get_selection();
3217 
3218    video_driver_get_size(&width, &height);
3219 
3220    /* Mimic the layout of the PSP instead of the PS3 on tiny screens */
3221    if (width > 320 && height > 240)
3222       stripes_layout_ps3(stripes, width, height);
3223    else
3224       stripes_layout_psp(stripes, width);
3225 
3226    current = (unsigned)selection;
3227    end     = (unsigned)menu_entries_get_size();
3228 
3229    for (i = 0; i < end; i++)
3230    {
3231       float ia         = stripes->items_passive_alpha;
3232       float iz         = stripes->items_passive_zoom;
3233       stripes_node_t *node = (stripes_node_t*)file_list_get_userdata_at_offset(
3234             selection_buf, i);
3235 
3236       if (!node)
3237          continue;
3238 
3239       if (i == current)
3240       {
3241          ia             = stripes->items_active_alpha;
3242          iz             = stripes->items_active_alpha;
3243       }
3244 
3245       node->alpha       = ia;
3246       node->label_alpha = ia;
3247       node->zoom        = iz;
3248       node->y           = stripes_item_y(stripes, i, current);
3249    }
3250 
3251    if (stripes->depth <= 1)
3252       return;
3253 
3254    current = (unsigned)stripes->selection_ptr_old;
3255    end     = (unsigned)stripes->selection_buf_old.size;
3256 
3257    for (i = 0; i < end; i++)
3258    {
3259       float         ia = 0;
3260       float         iz = stripes->items_passive_zoom;
3261       stripes_node_t *node = (stripes_node_t*)file_list_get_userdata_at_offset(
3262             &stripes->selection_buf_old, i);
3263 
3264       if (!node)
3265          continue;
3266 
3267       if (i == current)
3268       {
3269          ia             = stripes->items_active_alpha;
3270          iz             = stripes->items_active_alpha;
3271       }
3272 
3273       node->alpha       = ia;
3274       node->label_alpha = 0;
3275       node->zoom        = iz;
3276       node->y           = stripes_item_y(stripes, i, current);
3277       node->x           = stripes->icon_size * 1 * -2;
3278    }
3279 }
3280 
stripes_init(void ** userdata,bool video_is_threaded)3281 static void *stripes_init(void **userdata, bool video_is_threaded)
3282 {
3283    unsigned width, height;
3284    int i;
3285    stripes_handle_t *stripes  = NULL;
3286    settings_t *settings       = config_get_ptr();
3287    menu_handle_t *menu        = (menu_handle_t*)calloc(1, sizeof(*menu));
3288    float scale_value          = settings->floats.menu_scale_factor * 100.0f;
3289 
3290    /* scaling multiplier formulas made from these values:     */
3291    /* stripes_scale 50 = {2.5, 2.5,   2, 1.7, 2.5,   4, 2.4, 2.5} */
3292    /* stripes_scale 75 = {  2, 1.6, 1.6, 1.4, 1.5, 2.3, 1.9, 1.3} */
3293    if (scale_value < 100)
3294    {
3295    /* text length & word wrap (base 35 apply to file browser, 1st column) */
3296       stripes_scale_mod[0] = -0.03 * scale_value + 4.083;
3297    /* playlist text length when thumbnail is ON (small, base 40) */
3298       stripes_scale_mod[1] = -0.03 * scale_value + 3.95;
3299    /* playlist text length when thumbnail is OFF (large, base 70) */
3300       stripes_scale_mod[2] = -0.02 * scale_value + 3.033;
3301    /* sub-label length & word wrap */
3302       stripes_scale_mod[3] = -0.014 * scale_value + 2.416;
3303    /* thumbnail size & vertical margin from top */
3304       stripes_scale_mod[4] = -0.03 * scale_value + 3.916;
3305    /* thumbnail horizontal left margin (horizontal positioning) */
3306       stripes_scale_mod[5] = -0.06 * scale_value + 6.933;
3307    /* margin before 2nd column start (shaders parameters, cheats...) */
3308       stripes_scale_mod[6] = -0.028 * scale_value + 3.866;
3309    /* text length & word wrap (base 35 apply to 2nd column in cheats, shaders, etc) */
3310       stripes_scale_mod[7] = 134.179 * pow(scale_value, -1.0778);
3311 
3312       for (i = 0; i < 8; i++)
3313          if (stripes_scale_mod[i] < 1)
3314             stripes_scale_mod[i] = 1;
3315    }
3316 
3317    if (!menu)
3318       goto error;
3319 
3320    video_driver_get_size(&width, &height);
3321 
3322    stripes = (stripes_handle_t*)calloc(1, sizeof(stripes_handle_t));
3323 
3324    if (!stripes)
3325       goto error;
3326 
3327    *userdata = stripes;
3328 
3329    if (!file_list_initialize(&stripes->selection_buf_old))
3330       goto error;
3331 
3332    stripes->categories_active_idx         = 0;
3333    stripes->categories_active_idx_old     = 0;
3334    stripes->x                             = 0;
3335    stripes->categories_x_pos              = 0;
3336    stripes->textures_arrow_alpha          = 0;
3337    stripes->depth                         = 1;
3338    stripes->old_depth                     = 1;
3339    stripes->alpha                         = 0;
3340 
3341    stripes->system_tab_end                = 0;
3342    stripes->tabs[stripes->system_tab_end]     = STRIPES_SYSTEM_TAB_MAIN;
3343    if (settings->bools.menu_content_show_settings && !settings->bools.kiosk_mode_enable)
3344       stripes->tabs[++stripes->system_tab_end] = STRIPES_SYSTEM_TAB_SETTINGS;
3345    if (settings->bools.menu_content_show_favorites)
3346       stripes->tabs[++stripes->system_tab_end] = STRIPES_SYSTEM_TAB_FAVORITES;
3347    if (settings->bools.menu_content_show_history)
3348       stripes->tabs[++stripes->system_tab_end] = STRIPES_SYSTEM_TAB_HISTORY;
3349 #ifdef HAVE_IMAGEVIEWER
3350    if (settings->bools.menu_content_show_images)
3351       stripes->tabs[++stripes->system_tab_end] = STRIPES_SYSTEM_TAB_IMAGES;
3352 #endif
3353    if (settings->bools.menu_content_show_music)
3354       stripes->tabs[++stripes->system_tab_end] = STRIPES_SYSTEM_TAB_MUSIC;
3355 #ifdef HAVE_FFMPEG
3356    if (settings->bools.menu_content_show_video)
3357       stripes->tabs[++stripes->system_tab_end] = STRIPES_SYSTEM_TAB_VIDEO;
3358 #endif
3359 #ifdef HAVE_NETWORKING
3360    if (settings->bools.menu_content_show_netplay)
3361       stripes->tabs[++stripes->system_tab_end] = STRIPES_SYSTEM_TAB_NETPLAY;
3362 #endif
3363 
3364    if (settings->bools.menu_content_show_add && !settings->bools.kiosk_mode_enable)
3365       stripes->tabs[++stripes->system_tab_end] = STRIPES_SYSTEM_TAB_ADD;
3366 
3367    menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL);
3368 
3369    /* TODO/FIXME - we don't use framebuffer at all
3370     * for XMB, we should refactor this dependency
3371     * away. */
3372 
3373    gfx_display_set_width(width);
3374    gfx_display_set_height(height);
3375 
3376    gfx_display_init_white_texture(gfx_display_white_texture);
3377 
3378    file_list_initialize(&stripes->horizontal_list);
3379    stripes_init_horizontal_list(stripes);
3380 
3381    /* set word_wrap function pointer */
3382    stripes->word_wrap = msg_hash_get_wideglyph_str() ? word_wrap_wideglyph : word_wrap;
3383 
3384    return menu;
3385 
3386 error:
3387    if (menu)
3388       free(menu);
3389 
3390    if (stripes)
3391    {
3392       stripes_free_list_nodes(&stripes->selection_buf_old, false);
3393       stripes_free_list_nodes(&stripes->horizontal_list, false);
3394       file_list_deinitialize(&stripes->selection_buf_old);
3395       file_list_deinitialize(&stripes->horizontal_list);
3396    }
3397    return NULL;
3398 }
3399 
stripes_free(void * data)3400 static void stripes_free(void *data)
3401 {
3402    stripes_handle_t *stripes = (stripes_handle_t*)data;
3403 
3404    if (stripes)
3405    {
3406       stripes_free_list_nodes(&stripes->selection_buf_old, false);
3407       stripes_free_list_nodes(&stripes->horizontal_list, false);
3408       file_list_deinitialize(&stripes->selection_buf_old);
3409       file_list_deinitialize(&stripes->horizontal_list);
3410 
3411       video_coord_array_free(&stripes->raster_block.carr);
3412       video_coord_array_free(&stripes->raster_block2.carr);
3413 
3414       if (!string_is_empty(stripes->box_message))
3415          free(stripes->box_message);
3416       if (!string_is_empty(stripes->thumbnail_system))
3417          free(stripes->thumbnail_system);
3418       if (!string_is_empty(stripes->thumbnail_content))
3419          free(stripes->thumbnail_content);
3420       if (!string_is_empty(stripes->savestate_thumbnail_file_path))
3421          free(stripes->savestate_thumbnail_file_path);
3422       if (!string_is_empty(stripes->thumbnail_file_path))
3423          free(stripes->thumbnail_file_path);
3424       if (!string_is_empty(stripes->left_thumbnail_file_path))
3425          free(stripes->left_thumbnail_file_path);
3426       if (!string_is_empty(stripes->bg_file_path))
3427          free(stripes->bg_file_path);
3428    }
3429 
3430    if (gfx_display_white_texture)
3431       video_driver_texture_unload(&gfx_display_white_texture);
3432 
3433    font_driver_bind_block(NULL, NULL);
3434 }
3435 
stripes_context_bg_destroy(stripes_handle_t * stripes)3436 static void stripes_context_bg_destroy(stripes_handle_t *stripes)
3437 {
3438    if (!stripes)
3439       return;
3440    video_driver_texture_unload(&stripes->textures.bg);
3441    video_driver_texture_unload(&gfx_display_white_texture);
3442 }
3443 
stripes_load_image(void * userdata,void * data,enum menu_image_type type)3444 static bool stripes_load_image(void *userdata, void *data, enum menu_image_type type)
3445 {
3446    stripes_handle_t *stripes = (stripes_handle_t*)userdata;
3447 
3448    if (!stripes || !data)
3449       return false;
3450 
3451    switch (type)
3452    {
3453       case MENU_IMAGE_NONE:
3454          break;
3455       case MENU_IMAGE_WALLPAPER:
3456          stripes_context_bg_destroy(stripes);
3457          video_driver_texture_unload(&stripes->textures.bg);
3458          video_driver_texture_load(data,
3459                TEXTURE_FILTER_MIPMAP_LINEAR,
3460                &stripes->textures.bg);
3461          if (gfx_display_white_texture)
3462             video_driver_texture_unload(&gfx_display_white_texture);
3463          gfx_display_init_white_texture(gfx_display_white_texture);
3464          break;
3465       case MENU_IMAGE_THUMBNAIL:
3466          {
3467             struct texture_image *img  = (struct texture_image*)data;
3468             stripes->thumbnail_height      = stripes->thumbnail_width
3469                * (float)img->height / (float)img->width;
3470             video_driver_texture_unload(&stripes->thumbnail);
3471             video_driver_texture_load(data,
3472                   TEXTURE_FILTER_MIPMAP_LINEAR, &stripes->thumbnail);
3473          }
3474          break;
3475       case MENU_IMAGE_LEFT_THUMBNAIL:
3476          {
3477             struct texture_image *img  = (struct texture_image*)data;
3478             stripes->left_thumbnail_height      = stripes->left_thumbnail_width
3479                * (float)img->height / (float)img->width;
3480             video_driver_texture_unload(&stripes->left_thumbnail);
3481             video_driver_texture_load(data,
3482                   TEXTURE_FILTER_MIPMAP_LINEAR, &stripes->left_thumbnail);
3483          }
3484          break;
3485       case MENU_IMAGE_SAVESTATE_THUMBNAIL:
3486          {
3487             struct texture_image *img       = (struct texture_image*)data;
3488             stripes->savestate_thumbnail_height = stripes->savestate_thumbnail_width
3489                * (float)img->height / (float)img->width;
3490             video_driver_texture_unload(&stripes->savestate_thumbnail);
3491             video_driver_texture_load(data,
3492                   TEXTURE_FILTER_MIPMAP_LINEAR, &stripes->savestate_thumbnail);
3493          }
3494          break;
3495    }
3496 
3497    return true;
3498 }
3499 
stripes_texture_path(unsigned id)3500 static const char *stripes_texture_path(unsigned id)
3501 {
3502    switch (id)
3503    {
3504       case STRIPES_TEXTURE_MAIN_MENU:
3505 #if defined(HAVE_LAKKA)
3506          return "lakka.png";
3507 #else
3508          return "retroarch.png";
3509 #endif
3510       case STRIPES_TEXTURE_SETTINGS:
3511          return "settings.png";
3512       case STRIPES_TEXTURE_HISTORY:
3513          return "history.png";
3514       case STRIPES_TEXTURE_FAVORITES:
3515          return "favorites.png";
3516       case STRIPES_TEXTURE_ADD_FAVORITE:
3517          return "add-favorite.png";
3518       case STRIPES_TEXTURE_MUSICS:
3519          return "musics.png";
3520 #ifdef HAVE_FFMPEG
3521       case STRIPES_TEXTURE_MOVIES:
3522          return "movies.png";
3523 #endif
3524 #ifdef HAVE_IMAGEVIEWER
3525       case STRIPES_TEXTURE_IMAGES:
3526          return "images.png";
3527 #endif
3528       case STRIPES_TEXTURE_SETTING:
3529          return "setting.png";
3530       case STRIPES_TEXTURE_SUBSETTING:
3531          return "subsetting.png";
3532       case STRIPES_TEXTURE_ARROW:
3533          return "arrow.png";
3534       case STRIPES_TEXTURE_RUN:
3535          return "run.png";
3536       case STRIPES_TEXTURE_CLOSE:
3537          return "close.png";
3538       case STRIPES_TEXTURE_RESUME:
3539          return "resume.png";
3540       case STRIPES_TEXTURE_CLOCK:
3541          return "clock.png";
3542       case STRIPES_TEXTURE_BATTERY_FULL:
3543          return "battery-full.png";
3544       case STRIPES_TEXTURE_BATTERY_CHARGING:
3545          return "battery-charging.png";
3546       case STRIPES_TEXTURE_POINTER:
3547          return "pointer.png";
3548       case STRIPES_TEXTURE_SAVESTATE:
3549          return "savestate.png";
3550       case STRIPES_TEXTURE_LOADSTATE:
3551          return "loadstate.png";
3552       case STRIPES_TEXTURE_UNDO:
3553          return "undo.png";
3554       case STRIPES_TEXTURE_CORE_INFO:
3555          return "core-infos.png";
3556       case STRIPES_TEXTURE_BLUETOOTH:
3557          return "bluetooth.png";
3558       case STRIPES_TEXTURE_WIFI:
3559          return "wifi.png";
3560       case STRIPES_TEXTURE_CORE_OPTIONS:
3561          return "core-options.png";
3562       case STRIPES_TEXTURE_INPUT_REMAPPING_OPTIONS:
3563          return "core-input-remapping-options.png";
3564       case STRIPES_TEXTURE_CHEAT_OPTIONS:
3565          return "core-cheat-options.png";
3566       case STRIPES_TEXTURE_DISK_OPTIONS:
3567          return "core-disk-options.png";
3568       case STRIPES_TEXTURE_SHADER_OPTIONS:
3569          return "core-shader-options.png";
3570       case STRIPES_TEXTURE_ACHIEVEMENT_LIST:
3571          return "achievement-list.png";
3572       case STRIPES_TEXTURE_SCREENSHOT:
3573          return "screenshot.png";
3574       case STRIPES_TEXTURE_RELOAD:
3575          return "reload.png";
3576       case STRIPES_TEXTURE_RENAME:
3577          return "rename.png";
3578       case STRIPES_TEXTURE_FILE:
3579          return "file.png";
3580       case STRIPES_TEXTURE_FOLDER:
3581          return "folder.png";
3582       case STRIPES_TEXTURE_ZIP:
3583          return "zip.png";
3584       case STRIPES_TEXTURE_MUSIC:
3585          return "music.png";
3586       case STRIPES_TEXTURE_FAVORITE:
3587          return "favorites-content.png";
3588       case STRIPES_TEXTURE_IMAGE:
3589          return "image.png";
3590       case STRIPES_TEXTURE_MOVIE:
3591          return "movie.png";
3592       case STRIPES_TEXTURE_CORE:
3593          return "core.png";
3594       case STRIPES_TEXTURE_RDB:
3595          return "database.png";
3596       case STRIPES_TEXTURE_CURSOR:
3597          return "cursor.png";
3598       case STRIPES_TEXTURE_SWITCH_ON:
3599          return "on.png";
3600       case STRIPES_TEXTURE_SWITCH_OFF:
3601          return "off.png";
3602       case STRIPES_TEXTURE_ADD:
3603          return "add.png";
3604 #ifdef HAVE_NETWORKING
3605       case STRIPES_TEXTURE_NETPLAY:
3606          return "netplay.png";
3607       case STRIPES_TEXTURE_ROOM:
3608          return "room.png";
3609       /* stub these out until we have the icons
3610       case STRIPES_TEXTURE_ROOM_LAN:
3611          return "room_lan.png";
3612       case STRIPES_TEXTURE_ROOM_MITM:
3613          return "room_mitm.png";
3614       */
3615 #endif
3616       case STRIPES_TEXTURE_KEY:
3617          return "key.png";
3618       case STRIPES_TEXTURE_KEY_HOVER:
3619          return "key-hover.png";
3620       case STRIPES_TEXTURE_DIALOG_SLICE:
3621          return "dialog-slice.png";
3622 
3623    }
3624 
3625    return NULL;
3626 }
3627 
stripes_context_reset_textures(stripes_handle_t * stripes,const char * iconpath)3628 static void stripes_context_reset_textures(
3629       stripes_handle_t *stripes, const char *iconpath)
3630 {
3631    unsigned i;
3632 
3633    for (i = 0; i < STRIPES_TEXTURE_LAST; i++)
3634       gfx_display_reset_textures_list(stripes_texture_path(i), iconpath, &stripes->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL);
3635 
3636    if (gfx_display_white_texture)
3637       video_driver_texture_unload(&gfx_display_white_texture);
3638    gfx_display_init_white_texture(gfx_display_white_texture);
3639 
3640    stripes->main_menu_node.icon     = stripes->textures.list[STRIPES_TEXTURE_MAIN_MENU];
3641    stripes->main_menu_node.alpha    = stripes->categories_active_alpha;
3642    stripes->main_menu_node.zoom     = stripes->categories_active_zoom;
3643 
3644    stripes->settings_tab_node.icon  = stripes->textures.list[STRIPES_TEXTURE_SETTINGS];
3645    stripes->settings_tab_node.alpha = stripes->categories_active_alpha;
3646    stripes->settings_tab_node.zoom  = stripes->categories_active_zoom;
3647 
3648    stripes->history_tab_node.icon   = stripes->textures.list[STRIPES_TEXTURE_HISTORY];
3649    stripes->history_tab_node.alpha  = stripes->categories_active_alpha;
3650    stripes->history_tab_node.zoom   = stripes->categories_active_zoom;
3651 
3652    stripes->favorites_tab_node.icon   = stripes->textures.list[STRIPES_TEXTURE_FAVORITES];
3653    stripes->favorites_tab_node.alpha  = stripes->categories_active_alpha;
3654    stripes->favorites_tab_node.zoom   = stripes->categories_active_zoom;
3655 
3656    stripes->music_tab_node.icon     = stripes->textures.list[STRIPES_TEXTURE_MUSICS];
3657    stripes->music_tab_node.alpha    = stripes->categories_active_alpha;
3658    stripes->music_tab_node.zoom     = stripes->categories_active_zoom;
3659 
3660 #ifdef HAVE_FFMPEG
3661    stripes->video_tab_node.icon     = stripes->textures.list[STRIPES_TEXTURE_MOVIES];
3662    stripes->video_tab_node.alpha    = stripes->categories_active_alpha;
3663    stripes->video_tab_node.zoom     = stripes->categories_active_zoom;
3664 #endif
3665 
3666 #ifdef HAVE_IMAGEVIEWER
3667    stripes->images_tab_node.icon    = stripes->textures.list[STRIPES_TEXTURE_IMAGES];
3668    stripes->images_tab_node.alpha   = stripes->categories_active_alpha;
3669    stripes->images_tab_node.zoom    = stripes->categories_active_zoom;
3670 #endif
3671 
3672    stripes->add_tab_node.icon       = stripes->textures.list[STRIPES_TEXTURE_ADD];
3673    stripes->add_tab_node.alpha      = stripes->categories_active_alpha;
3674    stripes->add_tab_node.zoom       = stripes->categories_active_zoom;
3675 
3676 #ifdef HAVE_NETWORKING
3677    stripes->netplay_tab_node.icon   = stripes->textures.list[STRIPES_TEXTURE_NETPLAY];
3678    stripes->netplay_tab_node.alpha  = stripes->categories_active_alpha;
3679    stripes->netplay_tab_node.zoom   = stripes->categories_active_zoom;
3680 #endif
3681 }
3682 
stripes_context_reset_background(const char * iconpath)3683 static void stripes_context_reset_background(const char *iconpath)
3684 {
3685    char path[PATH_MAX_LENGTH];
3686    settings_t *settings        = config_get_ptr();
3687    const char *path_menu_wp    = settings->paths.path_menu_wallpaper;
3688 
3689    path[0]                     = '\0';
3690 
3691    if (!string_is_empty(path_menu_wp))
3692       strlcpy(path, path_menu_wp, sizeof(path));
3693    else if (!string_is_empty(iconpath))
3694       fill_pathname_join(path, iconpath, "bg.png", sizeof(path));
3695 
3696    if (path_is_valid(path))
3697       task_push_image_load(path,
3698             video_driver_supports_rgba(), 0,
3699             menu_display_handle_wallpaper_upload, NULL);
3700 }
3701 
stripes_context_reset(void * data,bool is_threaded)3702 static void stripes_context_reset(void *data, bool is_threaded)
3703 {
3704    stripes_handle_t *stripes = (stripes_handle_t*)data;
3705 
3706    if (stripes)
3707    {
3708       char iconpath    [PATH_MAX_LENGTH];
3709       char bg_file_path[PATH_MAX_LENGTH];
3710       iconpath[0]       = bg_file_path[0] = '\0';
3711 
3712       fill_pathname_application_special(bg_file_path,
3713             sizeof(bg_file_path), APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_BG);
3714 
3715       if (!string_is_empty(bg_file_path))
3716       {
3717          if (!string_is_empty(stripes->bg_file_path))
3718             free(stripes->bg_file_path);
3719          stripes->bg_file_path = strdup(bg_file_path);
3720       }
3721 
3722       fill_pathname_application_special(iconpath, sizeof(iconpath),
3723             APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_ICONS);
3724 
3725       stripes_layout(stripes);
3726       stripes->font = gfx_display_font(p_disp, APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_FONT,
3727             stripes->font_size,
3728             is_threaded);
3729       stripes->font2 = gfx_display_font(p_disp, APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_FONT,
3730             stripes->font2_size,
3731             is_threaded);
3732       stripes_context_reset_textures(stripes, iconpath);
3733       stripes_context_reset_background(iconpath);
3734       stripes_context_reset_horizontal_list(stripes);
3735 
3736       if (!string_is_equal(stripes_thumbnails_ident('R'),
3737                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
3738          stripes_update_thumbnail_image(stripes);
3739       if (!string_is_equal(stripes_thumbnails_ident('R'),
3740                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
3741          stripes_update_thumbnail_image(stripes);
3742       stripes_update_savestate_thumbnail_image(stripes);
3743    }
3744    video_driver_monitor_reset();
3745 }
3746 
stripes_navigation_clear(void * data,bool pending_push)3747 static void stripes_navigation_clear(void *data, bool pending_push)
3748 {
3749    stripes_handle_t  *stripes  = (stripes_handle_t*)data;
3750    if (!pending_push)
3751       stripes_selection_pointer_changed(stripes, true);
3752 }
3753 
stripes_navigation_pointer_changed(void * data)3754 static void stripes_navigation_pointer_changed(void *data)
3755 {
3756    stripes_handle_t  *stripes  = (stripes_handle_t*)data;
3757    stripes_selection_pointer_changed(stripes, true);
3758 }
3759 
stripes_navigation_set(void * data,bool scroll)3760 static void stripes_navigation_set(void *data, bool scroll)
3761 {
3762    stripes_handle_t  *stripes  = (stripes_handle_t*)data;
3763    stripes_selection_pointer_changed(stripes, true);
3764 }
3765 
stripes_navigation_alphabet(void * data,size_t * unused)3766 static void stripes_navigation_alphabet(void *data, size_t *unused)
3767 {
3768    stripes_handle_t  *stripes  = (stripes_handle_t*)data;
3769    stripes_selection_pointer_changed(stripes, true);
3770 }
3771 
stripes_list_insert(void * userdata,file_list_t * list,const char * path,const char * fullpath,const char * unused,size_t list_size,unsigned entry_type)3772 static void stripes_list_insert(void *userdata,
3773       file_list_t *list,
3774       const char *path,
3775       const char *fullpath,
3776       const char *unused,
3777       size_t list_size,
3778       unsigned entry_type)
3779 {
3780    int current            = 0;
3781    int i                  = (int)list_size;
3782    stripes_node_t *node       = NULL;
3783    stripes_handle_t *stripes      = (stripes_handle_t*)userdata;
3784    size_t selection       = menu_navigation_get_selection();
3785 
3786    if (!stripes || !list)
3787       return;
3788 
3789    node = (stripes_node_t*)file_list_get_userdata_at_offset(list, i);
3790 
3791    if (!node)
3792       node = stripes_alloc_node();
3793 
3794    if (!node)
3795    {
3796       RARCH_ERR("XMB node could not be allocated.\n");
3797       return;
3798    }
3799 
3800    current           = (int)selection;
3801 
3802    if (!string_is_empty(fullpath))
3803    {
3804       if (node->fullpath)
3805          free(node->fullpath);
3806 
3807       node->fullpath = strdup(fullpath);
3808    }
3809 
3810    node->alpha       = stripes->items_passive_alpha;
3811    node->zoom        = stripes->items_passive_zoom;
3812    node->label_alpha = node->alpha;
3813    node->y           = stripes_item_y(stripes, i, current);
3814    node->x           = 0;
3815 
3816    if (i == current)
3817    {
3818       node->alpha       = stripes->items_active_alpha;
3819       node->label_alpha = stripes->items_active_alpha;
3820       node->zoom        = stripes->items_active_alpha;
3821    }
3822 
3823    list->list[i].userdata = node;
3824 }
3825 
stripes_list_clear(file_list_t * list)3826 static void stripes_list_clear(file_list_t *list)
3827 {
3828    uintptr_t tag = (uintptr_t)list;
3829 
3830    gfx_animation_kill_by_tag(&tag);
3831 
3832    stripes_free_list_nodes(list, false);
3833 }
3834 
stripes_list_free(file_list_t * list,size_t a,size_t b)3835 static void stripes_list_free(file_list_t *list, size_t a, size_t b)
3836 {
3837    stripes_list_clear(list);
3838 }
3839 
stripes_list_deep_copy(const file_list_t * src,file_list_t * dst,size_t first,size_t last)3840 static void stripes_list_deep_copy(const file_list_t *src, file_list_t *dst,
3841       size_t first, size_t last)
3842 {
3843    size_t i, j   = 0;
3844    uintptr_t tag = (uintptr_t)dst;
3845 
3846    gfx_animation_kill_by_tag(&tag);
3847 
3848    stripes_free_list_nodes(dst, true);
3849 
3850    file_list_clear(dst);
3851    file_list_reserve(dst, (last + 1) - first);
3852 
3853    for (i = first; i <= last; ++i)
3854    {
3855       struct item_file *d = &dst->list[j];
3856       struct item_file *s = &src->list[i];
3857 
3858       void *src_udata = s->userdata;
3859       void *src_adata = s->actiondata;
3860 
3861       *d       = *s;
3862       d->alt   = string_is_empty(d->alt)   ? NULL : strdup(d->alt);
3863       d->path  = string_is_empty(d->path)  ? NULL : strdup(d->path);
3864       d->label = string_is_empty(d->label) ? NULL : strdup(d->label);
3865 
3866       if (src_udata)
3867          dst->list[j].userdata = (void*)stripes_copy_node((const stripes_node_t*)src_udata);
3868 
3869       if (src_adata)
3870       {
3871          void *data = malloc(sizeof(menu_file_list_cbs_t));
3872          memcpy(data, src_adata, sizeof(menu_file_list_cbs_t));
3873          dst->list[j].actiondata = data;
3874       }
3875 
3876       ++j;
3877    }
3878 
3879    dst->size = j;
3880 }
3881 
stripes_list_cache(void * data,enum menu_list_type type,unsigned action)3882 static void stripes_list_cache(void *data, enum menu_list_type type, unsigned action)
3883 {
3884    size_t stack_size, list_size;
3885    stripes_handle_t      *stripes     = (stripes_handle_t*)data;
3886    file_list_t *menu_stack    = menu_entries_get_menu_stack_ptr(0);
3887    file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
3888    size_t selection           = menu_navigation_get_selection();
3889    settings_t *settings       = config_get_ptr();
3890 
3891    if (!stripes)
3892       return;
3893 
3894    /* Check whether to enable the horizontal animation. */
3895    if (settings->bools.menu_horizontal_animation)
3896    {
3897       unsigned first = 0, last = 0;
3898       unsigned height = 0;
3899       video_driver_get_size(NULL, &height);
3900 
3901       /* FIXME: this shouldn't be happening at all */
3902       if (selection >= selection_buf->size)
3903          selection = selection_buf->size ? selection_buf->size - 1 : 0;
3904 
3905       stripes->selection_ptr_old = selection;
3906 
3907       stripes_calculate_visible_range(stripes, height, selection_buf->size,
3908             stripes->selection_ptr_old, &first, &last);
3909 
3910       stripes_list_deep_copy(selection_buf,
3911             &stripes->selection_buf_old, first, last);
3912 
3913       stripes->selection_ptr_old -= first;
3914       last                   -= first;
3915       first                   = 0;
3916    }
3917    else
3918       stripes->selection_ptr_old = 0;
3919 
3920    list_size = stripes_list_get_size(stripes, MENU_LIST_HORIZONTAL)
3921       + stripes->system_tab_end;
3922 
3923    switch (type)
3924    {
3925       case MENU_LIST_PLAIN:
3926          break;
3927       case MENU_LIST_HORIZONTAL:
3928          stripes->categories_selection_ptr_old = stripes->categories_selection_ptr;
3929 
3930          switch (action)
3931          {
3932             case MENU_ACTION_LEFT:
3933                if (stripes->categories_selection_ptr == 0)
3934                {
3935                   stripes->categories_selection_ptr = list_size;
3936                   stripes->categories_active_idx    = (unsigned)(list_size - 1);
3937                }
3938                else
3939                   stripes->categories_selection_ptr--;
3940                break;
3941             default:
3942                if (stripes->categories_selection_ptr == list_size)
3943                {
3944                   stripes->categories_selection_ptr = 0;
3945                   stripes->categories_active_idx = 1;
3946                }
3947                else
3948                   stripes->categories_selection_ptr++;
3949                break;
3950          }
3951 
3952          stack_size = menu_stack->size;
3953 
3954          if (menu_stack->list[stack_size - 1].label)
3955             free(menu_stack->list[stack_size - 1].label);
3956          menu_stack->list[stack_size - 1].label = NULL;
3957 
3958          switch (stripes_get_system_tab(stripes, (unsigned)stripes->categories_selection_ptr))
3959          {
3960             case STRIPES_SYSTEM_TAB_MAIN:
3961                menu_stack->list[stack_size - 1].label =
3962                   strdup(msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU));
3963                menu_stack->list[stack_size - 1].type =
3964                   MENU_SETTINGS;
3965                break;
3966             case STRIPES_SYSTEM_TAB_SETTINGS:
3967                menu_stack->list[stack_size - 1].label =
3968                   strdup(msg_hash_to_str(MENU_ENUM_LABEL_SETTINGS_TAB));
3969                menu_stack->list[stack_size - 1].type =
3970                   MENU_SETTINGS_TAB;
3971                break;
3972 #ifdef HAVE_IMAGEVIEWER
3973             case STRIPES_SYSTEM_TAB_IMAGES:
3974                menu_stack->list[stack_size - 1].label =
3975                   strdup(msg_hash_to_str(MENU_ENUM_LABEL_IMAGES_TAB));
3976                menu_stack->list[stack_size - 1].type =
3977                   MENU_IMAGES_TAB;
3978                break;
3979 #endif
3980             case STRIPES_SYSTEM_TAB_MUSIC:
3981                menu_stack->list[stack_size - 1].label =
3982                   strdup(msg_hash_to_str(MENU_ENUM_LABEL_MUSIC_TAB));
3983                menu_stack->list[stack_size - 1].type =
3984                   MENU_MUSIC_TAB;
3985                break;
3986 #ifdef HAVE_FFMPEG
3987             case STRIPES_SYSTEM_TAB_VIDEO:
3988                menu_stack->list[stack_size - 1].label =
3989                   strdup(msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_TAB));
3990                menu_stack->list[stack_size - 1].type =
3991                   MENU_VIDEO_TAB;
3992                break;
3993 #endif
3994             case STRIPES_SYSTEM_TAB_HISTORY:
3995                menu_stack->list[stack_size - 1].label =
3996                   strdup(msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB));
3997                menu_stack->list[stack_size - 1].type =
3998                   MENU_HISTORY_TAB;
3999                break;
4000             case STRIPES_SYSTEM_TAB_FAVORITES:
4001                menu_stack->list[stack_size - 1].label =
4002                   strdup(msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB));
4003                menu_stack->list[stack_size - 1].type =
4004                   MENU_FAVORITES_TAB;
4005                break;
4006 #ifdef HAVE_NETWORKING
4007             case STRIPES_SYSTEM_TAB_NETPLAY:
4008                menu_stack->list[stack_size - 1].label =
4009                   strdup(msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB));
4010                menu_stack->list[stack_size - 1].type =
4011                   MENU_NETPLAY_TAB;
4012                break;
4013 #endif
4014             case STRIPES_SYSTEM_TAB_ADD:
4015                menu_stack->list[stack_size - 1].label =
4016                   strdup(msg_hash_to_str(MENU_ENUM_LABEL_ADD_TAB));
4017                menu_stack->list[stack_size - 1].type =
4018                   MENU_ADD_TAB;
4019                break;
4020             default:
4021                menu_stack->list[stack_size - 1].label =
4022                   strdup(msg_hash_to_str(MENU_ENUM_LABEL_HORIZONTAL_MENU));
4023                menu_stack->list[stack_size - 1].type =
4024                   MENU_SETTING_HORIZONTAL_MENU;
4025                break;
4026          }
4027          break;
4028       default:
4029          break;
4030    }
4031 }
4032 
stripes_context_destroy(void * data)4033 static void stripes_context_destroy(void *data)
4034 {
4035    unsigned i;
4036    stripes_handle_t *stripes   = (stripes_handle_t*)data;
4037 
4038    if (!stripes)
4039       return;
4040 
4041    for (i = 0; i < STRIPES_TEXTURE_LAST; i++)
4042       video_driver_texture_unload(&stripes->textures.list[i]);
4043 
4044    video_driver_texture_unload(&stripes->thumbnail);
4045    video_driver_texture_unload(&stripes->left_thumbnail);
4046    video_driver_texture_unload(&stripes->savestate_thumbnail);
4047 
4048    stripes_context_destroy_horizontal_list(stripes);
4049    stripes_context_bg_destroy(stripes);
4050 
4051    gfx_display_font_free(stripes->font);
4052    gfx_display_font_free(stripes->font2);
4053 
4054    stripes->font = NULL;
4055    stripes->font2 = NULL;
4056 }
4057 
stripes_toggle(void * userdata,bool menu_on)4058 static void stripes_toggle(void *userdata, bool menu_on)
4059 {
4060    gfx_animation_ctx_entry_t entry;
4061    bool tmp             = false;
4062    stripes_handle_t *stripes    = (stripes_handle_t*)userdata;
4063 
4064    if (!stripes)
4065       return;
4066 
4067    stripes->depth         = (int)stripes_list_get_size(stripes, MENU_LIST_PLAIN);
4068 
4069    if (!menu_on)
4070    {
4071       stripes->alpha = 0;
4072       return;
4073    }
4074 
4075    entry.duration     = STRIPES_DELAY * 2;
4076    entry.target_value = 1.0f;
4077    entry.subject      = &stripes->alpha;
4078    entry.easing_enum  = EASING_OUT_QUAD;
4079    /* TODO/FIXME - integer conversion resulted in change of sign */
4080    entry.tag          = -1;
4081    entry.cb           = NULL;
4082 
4083    gfx_animation_push(&entry);
4084 
4085    tmp = !menu_entries_ctl(MENU_ENTRIES_CTL_NEEDS_REFRESH, NULL);
4086 
4087    if (tmp)
4088       menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
4089    else
4090       menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL);
4091 
4092    stripes_toggle_horizontal_list(stripes);
4093 }
4094 
stripes_deferred_push_content_actions(menu_displaylist_info_t * info)4095 static int stripes_deferred_push_content_actions(menu_displaylist_info_t *info)
4096 {
4097    settings_t *settings = config_get_ptr();
4098    if (!menu_displaylist_ctl(
4099          DISPLAYLIST_HORIZONTAL_CONTENT_ACTIONS, info, settings))
4100       return -1;
4101    menu_displaylist_process(info);
4102    menu_displaylist_info_free(info);
4103    return 0;
4104 }
4105 
stripes_list_bind_init_compare_label(menu_file_list_cbs_t * cbs)4106 static int stripes_list_bind_init_compare_label(menu_file_list_cbs_t *cbs)
4107 {
4108    if (cbs && cbs->enum_idx != MSG_UNKNOWN)
4109    {
4110       switch (cbs->enum_idx)
4111       {
4112          case MENU_ENUM_LABEL_CONTENT_ACTIONS:
4113             cbs->action_deferred_push = stripes_deferred_push_content_actions;
4114             break;
4115          default:
4116             return -1;
4117       }
4118    }
4119 
4120    return 0;
4121 }
4122 
stripes_list_bind_init(menu_file_list_cbs_t * cbs,const char * path,const char * label,unsigned type,size_t idx)4123 static int stripes_list_bind_init(menu_file_list_cbs_t *cbs,
4124       const char *path, const char *label, unsigned type, size_t idx)
4125 {
4126    if (stripes_list_bind_init_compare_label(cbs) == 0)
4127       return 0;
4128 
4129    return -1;
4130 }
4131 
stripes_list_push(void * data,void * userdata,menu_displaylist_info_t * info,unsigned type)4132 static int stripes_list_push(void *data, void *userdata,
4133       menu_displaylist_info_t *info, unsigned type)
4134 {
4135    int ret                = -1;
4136    int i                  = 0;
4137    core_info_list_t *list = NULL;
4138 
4139    switch (type)
4140    {
4141       case DISPLAYLIST_LOAD_CONTENT_LIST:
4142          {
4143             settings_t *settings = config_get_ptr();
4144 
4145             menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
4146 
4147             menu_entries_append_enum(info->list,
4148                   msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES),
4149                   msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES),
4150                   MENU_ENUM_LABEL_FAVORITES,
4151                   MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0);
4152 
4153             core_info_get_list(&list);
4154             if (list->info_count > 0)
4155             {
4156                menu_entries_append_enum(info->list,
4157                      msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST),
4158                      msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST),
4159                      MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST,
4160                      MENU_SETTING_ACTION, 0, 0);
4161             }
4162 
4163             if (settings->bools.menu_content_show_playlists)
4164                menu_entries_append_enum(info->list,
4165                      msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB),
4166                      msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB),
4167                      MENU_ENUM_LABEL_PLAYLISTS_TAB,
4168                      MENU_SETTING_ACTION, 0, 0);
4169 
4170             if (frontend_driver_parse_drive_list(info->list, true) != 0)
4171                menu_entries_append_enum(info->list, "/",
4172                      msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
4173                      MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR,
4174                      MENU_SETTING_ACTION, 0, 0);
4175 
4176             if (!settings->bools.kiosk_mode_enable)
4177             {
4178                menu_entries_append_enum(info->list,
4179                      msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS),
4180                      msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS),
4181                      MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS,
4182                      MENU_SETTING_ACTION, 0, 0);
4183             }
4184 
4185             info->need_push    = true;
4186             info->need_refresh = true;
4187             ret = 0;
4188          }
4189          break;
4190       case DISPLAYLIST_MAIN_MENU:
4191          {
4192             settings_t   *settings      = config_get_ptr();
4193             rarch_system_info_t *system = runloop_get_system_info();
4194             menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
4195 
4196             entry.data            = menu;
4197             entry.info            = info;
4198             entry.parse_type      = PARSE_ACTION;
4199             entry.add_empty_entry = false;
4200 
4201             if (rarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
4202             {
4203                if (!rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
4204                {
4205                   MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4206                         info->list,
4207                         MENU_ENUM_LABEL_CONTENT_SETTINGS,
4208                         PARSE_ACTION,
4209                         false);
4210                }
4211             }
4212             else
4213             {
4214                if (system->load_no_content)
4215                {
4216                   MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4217                         info->list,
4218                         MENU_ENUM_LABEL_START_CORE,
4219                         PARSE_ACTION,
4220                         false);
4221                }
4222 
4223 #ifndef HAVE_DYNAMIC
4224                if (frontend_driver_has_fork())
4225 #endif
4226                {
4227                   if (settings->bools.menu_show_load_core)
4228                   {
4229                      MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4230                            info->list,
4231                            MENU_ENUM_LABEL_CORE_LIST,
4232                            PARSE_ACTION,
4233                            false);
4234                   }
4235                }
4236             }
4237 
4238             if (settings->bools.menu_show_load_content)
4239             {
4240                MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4241                      info->list,
4242                      MENU_ENUM_LABEL_LOAD_CONTENT_LIST,
4243                      PARSE_ACTION,
4244                      false);
4245 
4246                if (menu_displaylist_has_subsystems())
4247                {
4248                   MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4249                         info->list,
4250                         MENU_ENUM_LABEL_SUBSYSTEM_SETTINGS,
4251                         PARSE_ACTION,
4252                         false);
4253                }
4254             }
4255 
4256             MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4257                   info->list,
4258                   MENU_ENUM_LABEL_ADD_CONTENT_LIST,
4259                   PARSE_ACTION,
4260                   false);
4261 #if defined(HAVE_NETWORKING)
4262             {
4263                settings_t *settings      = config_get_ptr();
4264                if (settings->bools.menu_show_online_updater && !settings->bools.kiosk_mode_enable)
4265                {
4266                   MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4267                         info->list,
4268                         MENU_ENUM_LABEL_ONLINE_UPDATER,
4269                         PARSE_ACTION,
4270                         false);
4271                }
4272             }
4273 #endif
4274             if (!settings->bools.menu_content_show_settings && !string_is_empty(settings->paths.menu_content_show_settings_password))
4275             {
4276                MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4277                      info->list,
4278                      MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS,
4279                      PARSE_ACTION,
4280                      false);
4281             }
4282 
4283             if (settings->bools.kiosk_mode_enable && !string_is_empty(settings->paths.kiosk_mode_password))
4284             {
4285                MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4286                      info->list,
4287                      MENU_ENUM_LABEL_MENU_DISABLE_KIOSK_MODE,
4288                      PARSE_ACTION,
4289                      false);
4290             }
4291 
4292             if (settings->bools.menu_show_information)
4293             {
4294                MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4295                      info->list,
4296                      MENU_ENUM_LABEL_INFORMATION_LIST,
4297                      PARSE_ACTION,
4298                      false);
4299             }
4300 
4301 #ifndef HAVE_DYNAMIC
4302             if (settings->bools.menu_show_restart_retroarch)
4303             {
4304                MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4305                      info->list,
4306                      MENU_ENUM_LABEL_RESTART_RETROARCH,
4307                      PARSE_ACTION,
4308                      false);
4309             }
4310 #endif
4311 
4312             if (settings->bools.menu_show_configurations && !settings->bools.kiosk_mode_enable)
4313             {
4314                MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4315                      info->list,
4316                      MENU_ENUM_LABEL_CONFIGURATIONS_LIST,
4317                      PARSE_ACTION,
4318                      false);
4319             }
4320 
4321             if (settings->bools.menu_show_help)
4322             {
4323                MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4324                      info->list,
4325                      MENU_ENUM_LABEL_HELP_LIST,
4326                      PARSE_ACTION,
4327                      false);
4328             }
4329 
4330 #if !defined(IOS)
4331             if (settings->bools.menu_show_quit_retroarch)
4332             {
4333                MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4334                      info->list,
4335                      MENU_ENUM_LABEL_QUIT_RETROARCH,
4336                      PARSE_ACTION,
4337                      false);
4338             }
4339 #endif
4340 
4341             if (settings->bools.menu_show_reboot)
4342             {
4343                MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4344                      info->list,
4345                      MENU_ENUM_LABEL_REBOOT,
4346                      PARSE_ACTION,
4347                      false);
4348             }
4349 
4350             MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
4351                   info->list,
4352                   MENU_ENUM_LABEL_SHUTDOWN,
4353                   PARSE_ACTION,
4354                   false);
4355             info->need_push    = true;
4356             ret = 0;
4357          }
4358          break;
4359    }
4360    return ret;
4361 }
4362 
stripes_menu_init_list(void * data)4363 static bool stripes_menu_init_list(void *data)
4364 {
4365    menu_displaylist_info_t info;
4366    settings_t *settings         = config_get_ptr();
4367 
4368    file_list_t *menu_stack      = menu_entries_get_menu_stack_ptr(0);
4369    file_list_t *selection_buf   = menu_entries_get_selection_buf_ptr(0);
4370 
4371    menu_displaylist_info_init(&info);
4372 
4373    info.label                   = strdup(
4374          msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU));
4375    info.exts                    = strdup("lpl");
4376    info.type_default            = FILE_TYPE_PLAIN;
4377    info.enum_idx                = MENU_ENUM_LABEL_MAIN_MENU;
4378 
4379    menu_entries_append_enum(menu_stack, info.path,
4380          info.label,
4381          MENU_ENUM_LABEL_MAIN_MENU,
4382          info.type, info.flags, 0);
4383 
4384    info.list  = selection_buf;
4385 
4386    if (!menu_displaylist_ctl(DISPLAYLIST_MAIN_MENU, &info, settings))
4387       goto error;
4388 
4389    info.need_push = true;
4390 
4391    if (!menu_displaylist_process(&info))
4392       goto error;
4393 
4394    menu_displaylist_info_free(&info);
4395    return true;
4396 
4397 error:
4398    menu_displaylist_info_free(&info);
4399    return false;
4400 }
4401 
stripes_pointer_up(void * userdata,unsigned x,unsigned y,unsigned ptr,enum menu_input_pointer_gesture gesture,menu_file_list_cbs_t * cbs,menu_entry_t * entry,unsigned action)4402 static int stripes_pointer_up(void *userdata,
4403       unsigned x, unsigned y, unsigned ptr,
4404       enum menu_input_pointer_gesture gesture,
4405       menu_file_list_cbs_t *cbs,
4406       menu_entry_t *entry, unsigned action)
4407 {
4408    stripes_handle_t *stripes = (stripes_handle_t*)userdata;
4409    size_t selection          = menu_navigation_get_selection();
4410 
4411    switch (gesture)
4412    {
4413       case MENU_INPUT_GESTURE_TAP:
4414       case MENU_INPUT_GESTURE_SHORT_PRESS:
4415          {
4416             /* Normal pointer input */
4417             gfx_display_t *p_disp  = disp_get_ptr();
4418             unsigned header_height = p_disp->header_height;
4419 
4420             if (y < header_height)
4421                return (unsigned)generic_menu_entry_action(stripes,
4422                      entry, selection, MENU_ACTION_CANCEL);
4423             else if (ptr <= (menu_entries_get_size() - 1))
4424             {
4425                if (ptr == selection && cbs && cbs->action_select)
4426                   return (unsigned)generic_menu_entry_action(stripes,
4427                         entry, selection, MENU_ACTION_SELECT);
4428 
4429                menu_navigation_set_selection(ptr);
4430                stripes_navigation_set(stripes, false);
4431             }
4432          }
4433          break;
4434       case MENU_INPUT_GESTURE_LONG_PRESS:
4435          /* 'Reset to default' action */
4436          if ((ptr <= (menu_entries_get_size() - 1)) &&
4437              (ptr == selection))
4438             return generic_menu_entry_action(stripes,
4439                   entry, selection, MENU_ACTION_START);
4440          break;
4441       default:
4442          /* Ignore input */
4443          break;
4444    }
4445 
4446    return 0;
4447 }
4448 
4449 menu_ctx_driver_t menu_ctx_stripes = {
4450    NULL,
4451    stripes_messagebox,
4452    stripes_render,
4453    stripes_frame,
4454    stripes_init,
4455    stripes_free,
4456    stripes_context_reset,
4457    stripes_context_destroy,
4458    stripes_populate_entries,
4459    stripes_toggle,
4460    stripes_navigation_clear,
4461    stripes_navigation_pointer_changed,
4462    stripes_navigation_pointer_changed,
4463    stripes_navigation_set,
4464    stripes_navigation_pointer_changed,
4465    stripes_navigation_alphabet,
4466    stripes_navigation_alphabet,
4467    stripes_menu_init_list,
4468    stripes_list_insert,
4469    NULL,
4470    stripes_list_free,
4471    stripes_list_clear,
4472    stripes_list_cache,
4473    stripes_list_push,
4474    stripes_list_get_selection,
4475    stripes_list_get_size,
4476    stripes_list_get_entry,
4477    NULL,
4478    stripes_list_bind_init,
4479    stripes_load_image,
4480    "stripes",
4481    stripes_environ,
4482    stripes_update_thumbnail_path,
4483    stripes_update_thumbnail_image,
4484    stripes_refresh_thumbnail_image,
4485    stripes_set_thumbnail_system,
4486    stripes_get_thumbnail_system,
4487    stripes_set_thumbnail_content,
4488    stripes_osk_ptr_at_pos,
4489    stripes_update_savestate_thumbnail_path,
4490    stripes_update_savestate_thumbnail_image,
4491    NULL,                                     /* pointer_down */
4492    stripes_pointer_up,                       /* pointer_up   */
4493    generic_menu_entry_action
4494 };
4495