Exemplo n.º 1
0
static int action_right_scroll(unsigned type, const char *label,
      bool wraparound)
{
   size_t selection;
   size_t scroll_accel   = 0;
   unsigned scroll_speed = 0, fast_scroll_speed = 0;
   if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection))
      return false;
   if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SCROLL_ACCEL, &scroll_accel))
      return false;

   scroll_speed      = (MAX(scroll_accel, 2) - 2) / 4 + 1;
   fast_scroll_speed = 4 + 4 * scroll_speed;

   if (selection  + fast_scroll_speed < (menu_entries_get_size()))
   {
      size_t idx  = selection + fast_scroll_speed;
      bool scroll = true;
      menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx);
      menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll);
   }
   else
   {
      if ((menu_entries_get_size() > 0))
         menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_LAST, NULL);
   }

   return 0;
}
Exemplo n.º 2
0
static int zarch_zui_render_lay_root_recent(zui_t *zui, struct zui_tabbed *tabbed)
{
   if (zarch_zui_tab(zui, tabbed, "Recent", 0))
   {
      static int gamepad_index = 0;
      unsigned size = menu_entries_get_size();
      unsigned i, j = 0;

      if (zarch_zui_gamepad_input(zui, &gamepad_index,
               &zui->recent_dlist_first, 0))
         zui->recent_dlist_first = gamepad_index;

      for (i = zui->recent_dlist_first; i < size; ++i)
      {
         menu_entry_t entry;

         menu_entry_get(&entry, 0, i, NULL, true);

         if (zarch_zui_list_item(zui, tabbed, 0, 
                  tabbed->tabline_size + j * ZUI_ITEM_SIZE_PX,
                  entry.path, i, entry.value, gamepad_index == (signed)i))
         {
            if (menu_entry_action(&entry, i, MENU_ACTION_OK))
               return 1;
         }

         j++;
      }

   }

   return 0;
}
Exemplo n.º 3
0
/**
 * Before a refresh, we could have deleted a
 * file on disk, causing selection_ptr to
 * suddendly be out of range.
 *
 * Ensure it doesn't overflow.
 **/
void menu_entries_refresh(file_list_t *list)
{
   size_t list_size, selection;
   if (!list)
      return;
   if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection))
      return;

   menu_entries_build_scroll_indices(list);

   list_size = menu_entries_get_size();

   if ((selection >= list_size) && list_size)
   {
      size_t idx  = list_size - 1;
      bool scroll = true;
      menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx);
      menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll);
   }
   else if (!list_size)
   {
      bool pending_push = true;
      menu_navigation_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
   }
}
Exemplo n.º 4
0
static int mui_pointer_tap(void *userdata,
      unsigned x, unsigned y, 
      unsigned ptr, menu_file_list_cbs_t *cbs,
      menu_entry_t *entry, unsigned action)
{
   size_t selection, idx;
   unsigned header_height, width, height, i;
   bool scroll                = false;
   mui_handle_t *mui          = (mui_handle_t*)userdata;
   file_list_t *menu_stack    = menu_entries_get_menu_stack_ptr(0);
   file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);

   if (!mui)
      return 0;

   video_driver_get_size(&width, &height);

   menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection);
   menu_display_ctl(MENU_DISPLAY_CTL_HEADER_HEIGHT, &header_height);

   if (y < header_height)
   {
      menu_entries_pop_stack(&selection, 0);
      menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &selection);
   }
   else if (y > height - mui->tabs_height)
   {
      for (i = 0; i <= MUI_SYSTEM_TAB_END; i++)
      {
         unsigned tab_width = width / (MUI_SYSTEM_TAB_END + 1);
         unsigned start = tab_width * i;

         if ((x >= start) && (x < (start + tab_width)))
         {
            mui->categories.selection_ptr = i;

            mui_preswitch_tabs(mui, action);

            if (cbs && cbs->action_content_list_switch)
               return cbs->action_content_list_switch(selection_buf, menu_stack,
                     "", "", 0);
         }
      }
   }
   else if (ptr <= (menu_entries_get_size() - 1))
   {
      if (ptr == selection && cbs && cbs->action_select)
         return menu_entry_action(entry, selection, MENU_ACTION_SELECT);

      idx  = ptr;

      menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx);
      menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll);
   }

   return 0;
}
Exemplo n.º 5
0
static int action_bind_down_generic(unsigned type, const char *label)
{
   size_t scroll_accel   = 0;
   unsigned scroll_speed  = 0;
   if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SCROLL_ACCEL, &scroll_accel))
      return -1;

   scroll_speed = (max(scroll_accel, 2) - 2) / 4 + 1;

   if (menu_entries_get_size() <= 0)
      return 0;

   menu_navigation_ctl(MENU_NAVIGATION_CTL_INCREMENT, &scroll_speed);

   return 0;
}
Exemplo n.º 6
0
void nk_menu_wnd_test(nk_menu_handle_t *zr)
{
   struct nk_panel layout;
   struct nk_context *ctx = &zr->ctx;
   const int id           = ZRMENU_WND_TEST;
   settings_t *settings   = config_get_ptr();

   if (nk_begin(ctx, &layout, "Test", nk_rect(140, 90, 500, 600),
         NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_MOVABLE|
         NK_WINDOW_SCALABLE|NK_WINDOW_BORDER))
   {
      unsigned size;
      struct nk_panel combo;
      menu_entry_t entry;
      static const char *themes[] = {"Dark", "Light"};
      enum   nk_menu_theme old     = zr->theme;

      nk_layout_row_dynamic(ctx, 30, 2);

      nk_layout_row_dynamic(ctx, 30, 4);
      //nk_checkbox_bool(ctx, "Show FPS", &(settings->fps_show));
      //nk_checkbox_bool(ctx, "Show FPS", &(settings->fps_show));
      //nk_checkbox_bool(ctx, "Show FPS", &(settings->fps_show));
      //nk_checkbox_bool(ctx, "Show FPS", &(settings->fps_show));
      nk_layout_row_dynamic(ctx, 30, 2);
      nk_label(ctx, "Volume:", NK_TEXT_LEFT);
      nk_slider_float(ctx, -80, &settings->audio.volume, 12, 0.5);
      nk_layout_row_dynamic(ctx, 30, 1);
      nk_property_int(ctx, "Max Users:", 1, (int*)&(settings->input.max_users),
         MAX_USERS, 1, 1);


      nk_label(ctx, "History:", NK_TEXT_LEFT);

      size = menu_entries_get_size();
   }
   /* save position and size to restore after context reset */
   nk_menu_set_state(zr, id, nk_window_get_position(ctx), nk_window_get_size(ctx));
   nk_end(ctx);
}
Exemplo n.º 7
0
static int zarch_zui_render_lay_root_recent(zui_t *zui, struct zui_tabbed *tabbed)
{
   if (zarch_zui_tab(zui, tabbed, "Recent", 0))
   {
      static int gamepad_index = 0;
      unsigned size = menu_entries_get_size();
      unsigned i, j = 0;

      if (zarch_zui_gamepad_input(zui, &gamepad_index,
               &zui->recent_dlist_first, 0))
         zui->recent_dlist_first = gamepad_index;

      for (i = zui->recent_dlist_first; i < size; ++i)
      {
         char rich_label[PATH_MAX_LENGTH];
         char entry_value[PATH_MAX_LENGTH];
         menu_entry_t entry                = {{0}};

         rich_label[0] = entry_value[0]    = '\0';

         menu_entry_get(&entry, 0, i, NULL, true);
         menu_entry_get_rich_label(i, rich_label, sizeof(rich_label));
         menu_entry_get_value(i, NULL, entry_value,sizeof(entry_value));

         if (zarch_zui_list_item(zui, tabbed, 0, 
                  tabbed->tabline_size + j * ZUI_ITEM_SIZE_PX,
                  rich_label, i, entry_value, gamepad_index == (signed)i))
         {
            if (menu_entry_action(&entry, i, MENU_ACTION_OK))
               return 1;
         }

         j++;
      }

   }

   return 0;
}
Exemplo n.º 8
0
static int zarch_zui_render_lay_root_recent(zui_t *zui, zui_tabbed_t *tabbed)
{
   if (zarch_zui_tab(zui, tabbed, "Recent", 0))
   {
      unsigned size = menu_entries_get_size();
      unsigned i, j = 0;

      zui->recent_dlist_first += zui->mouse.wheel;

      if (zui->recent_dlist_first < 0)
         zui->recent_dlist_first = 0;
      else if (zui->recent_dlist_first > size - 5)
         zui->recent_dlist_first = size - 5;

      zui->recent_dlist_first = min(max(zui->recent_dlist_first, 0), size - 5);

      for (i = zui->recent_dlist_first; i < size; ++i)
      {
         menu_entry_t entry;

         menu_entry_get(&entry, 0, i, NULL, true);

         if (zarch_zui_list_item(zui, tabbed, 0, tabbed->tabline_size + j * 54,
                  entry.path, i, entry.value))
         {
            zui->pending_action_ok.enable      = true;
            zui->pending_action_ok.idx         = i;
            return 1;
         }

         j++;
      }
   }

   return 0;
}
Exemplo n.º 9
0
/**
 * Before a refresh, we could have deleted a
 * file on disk, causing selection_ptr to
 * suddendly be out of range.
 *
 * Ensure it doesn't overflow.
 **/
static bool menu_entries_refresh(void *data)
{
   size_t list_size;
   file_list_t *list = (file_list_t*)data;
   size_t selection  = menu_navigation_get_selection();

   menu_entries_build_scroll_indices(list);

   list_size = menu_entries_get_size();

   if ((selection >= list_size) && list_size)
   {
      size_t idx  = list_size - 1;
      menu_navigation_set_selection(idx);
      menu_driver_navigation_set(true);
   }
   else if (!list_size)
   {
      bool pending_push = true;
      menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
   }

   return true;
}
Exemplo n.º 10
0
static int menu_input_mouse_post_iterate(uint64_t *input_mouse,
      menu_file_list_cbs_t *cbs, unsigned action)
{
   settings_t *settings       = config_get_ptr();
   static bool mouse_oldleft  = false;
   static bool mouse_oldright = false;

   if (
         !settings->menu.mouse.enable
#ifdef HAVE_OVERLAY
         || (settings->input.overlay_enable && input_overlay_is_alive(NULL))
#endif
         )
   {
      /* HACK: Need to lie to avoid false hits if mouse is held 
       * when entering the RetroArch window. */

      /* This happens if, for example, someone double clicks the 
       * window border to maximize it.
       *
       * The proper fix is, of course, triggering on WM_LBUTTONDOWN 
       * rather than this state change. */
      mouse_oldleft   = true;
      mouse_oldright  = true;
      return 0;
   }

   if (menu_input_mouse_state(MENU_MOUSE_LEFT_BUTTON))
   {
      if (!mouse_oldleft)
      {
         size_t selection;
         menu_input_t *menu_input = menu_input_get_ptr();

         menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection);

         BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_BUTTON_L);

         mouse_oldleft = true;

         if ((menu_input->mouse.ptr == selection) && cbs && cbs->action_select)
         {
            BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_BUTTON_L_TOGGLE);
         }
         else if (menu_input->mouse.ptr <= (menu_entries_get_size() - 1))
         {
            BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_BUTTON_L_SET_NAVIGATION);
         }
      }
   }
   else
      mouse_oldleft = false;

   if (menu_input_mouse_state(MENU_MOUSE_RIGHT_BUTTON))
   {
      if (!mouse_oldright)
      {
         mouse_oldright = true;
         BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_BUTTON_R);
      }
   }
   else
      mouse_oldright = false;

   if (menu_input_mouse_state(MENU_MOUSE_WHEEL_DOWN))
   {
      BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_WHEEL_DOWN);
   }

   if (menu_input_mouse_state(MENU_MOUSE_WHEEL_UP))
   {
      BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_WHEEL_UP);
   }

   if (menu_input_mouse_state(MENU_MOUSE_HORIZ_WHEEL_DOWN))
   {
      BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_HORIZ_WHEEL_DOWN);
   }

   if (menu_input_mouse_state(MENU_MOUSE_HORIZ_WHEEL_UP))
   {
      BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_HORIZ_WHEEL_UP);
   }

   return 0;
}
Exemplo n.º 11
0
/**
 * menu_iterate:
 * @input                    : input sample for this frame
 * @old_input                : input sample of the previous frame
 * @trigger_input            : difference' input sample - difference
 *                             between 'input' and 'old_input'
 *
 * Runs RetroArch menu for one frame.
 *
 * Returns: 0 on success, -1 if we need to quit out of the loop. 
 **/
int generic_menu_iterate(enum menu_action action)
{
   size_t selection;
   menu_entry_t entry;
   enum action_iterate_type iterate_type;
   const char *label          = NULL;
   int ret                    = 0;
   uint32_t label_hash        = 0;
   uint32_t hash              = 0;
   menu_handle_t *menu        = menu_driver_get_ptr();
   file_list_t *menu_stack    = menu_entries_get_menu_stack_ptr();
   file_list_t *selection_buf = menu_entries_get_selection_buf_ptr();

   menu_entries_get_last_stack(NULL, &label, NULL, NULL);

   if (!menu)
      return 0;
   if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection))
      return 0;

   menu->menu_state.msg[0]   = '\0';
   hash                      = menu_hash_calculate(label);
   iterate_type              = action_iterate_type(hash);

   if (action != MENU_ACTION_NOOP || menu_entries_needs_refresh() || menu_display_ctl(MENU_DISPLAY_CTL_UPDATE_PENDING, NULL))
   {
      BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER);
   }

   switch (iterate_type)
   {
      case ITERATE_TYPE_HELP:
         ret = action_iterate_help(menu->menu_state.msg, sizeof(menu->menu_state.msg), label);
         BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
         BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
         if (ret == 1 || action == MENU_ACTION_OK)
            BIT64_SET(menu->state, MENU_STATE_POP_STACK);
         break;
      case ITERATE_TYPE_BIND:
         if (menu_input_key_bind_iterate(menu->menu_state.msg, sizeof(menu->menu_state.msg)))
         {
            menu_entries_pop_stack(&selection);
            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &selection);
         }
         else
            BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
         break;
      case ITERATE_TYPE_INFO:
         {
            menu_file_list_cbs_t *cbs = menu_entries_get_actiondata_at_offset(selection_buf, selection);
            rarch_setting_t *setting  = cbs->setting;

            if (setting)
            {
               char needle[PATH_MAX_LENGTH];
               strlcpy(needle, menu_setting_get_name(setting), sizeof(needle));
               label_hash       = menu_hash_calculate(needle);
            }

            ret = menu_hash_get_help(label_hash, menu->menu_state.msg, sizeof(menu->menu_state.msg));
         }
         BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
         BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
         if (action == MENU_ACTION_OK)
            BIT64_SET(menu->state, MENU_STATE_POP_STACK);
         break;
      case ITERATE_TYPE_DEFAULT:
         /* FIXME: Crappy hack, needed for mouse controls to not be completely broken
          * in case we press back.
          *
          * We need to fix this entire mess, mouse controls should not rely on a 
          * hack like this in order to work. */
         selection = max(min(selection, (menu_entries_get_size() - 1)), 0);

         menu_entry_get(&entry,    selection, NULL, false);
         ret = menu_entry_action(&entry, selection, (enum menu_action)action);

         if (ret)
            goto end;

         BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);

         /* Have to defer it so we let settings refresh. */
         if (menu->push_help_screen)
         {
            menu_displaylist_info_t info = {0};

            info.list = menu_stack;
            strlcpy(info.label,
                  menu_hash_to_str(MENU_LABEL_HELP),
                  sizeof(info.label));

            menu_displaylist_push_list(&info, DISPLAYLIST_HELP);
         }
         break;
   }

   BIT64_SET(menu->state, MENU_STATE_BLIT);

   if (BIT64_GET(menu->state, MENU_STATE_POP_STACK))
   {
      size_t new_selection_ptr = selection;
      menu_entries_pop_stack(&new_selection_ptr);
      menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &selection);
   }
   
   if (BIT64_GET(menu->state, MENU_STATE_POST_ITERATE))
      menu_input_post_iterate(&ret, action);

end:
   if (ret)
      return -1;
   return 0;
}
Exemplo n.º 12
0
/* Returns the last index (+1) of the menu entry list. */
size_t menu_entries_get_end(void)
{
   return menu_entries_get_size();
}
Exemplo n.º 13
0
bool menu_navigation_ctl(enum menu_navigation_ctl_state state, void *data)
{
   /* Quick jumping indices with L/R.
    * Rebuilt when parsing directory. */
   static struct scroll_indices
   {
      size_t list[2 * (26 + 2) + 1];
      unsigned size;
   } scroll_index;
   static unsigned scroll_acceleration    = 0;
   static size_t selection_ptr            = 0;

   switch (state)
   {
      case MENU_NAVIGATION_CTL_DEINIT:
         scroll_acceleration = 0;
         selection_ptr       = 0;
         memset(&scroll_index, 0, sizeof(struct scroll_indices));
         break;
      case MENU_NAVIGATION_CTL_CLEAR:
         {
            size_t idx         = 0;
            bool scroll        = true;

            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx);
            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll);
            menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_CLEAR, data);
         }
         break;
      case MENU_NAVIGATION_CTL_INCREMENT:
         {
            settings_t *settings   = config_get_ptr();
            unsigned *scroll_speed = (unsigned*)data;
            size_t  menu_list_size = menu_entries_get_size();

            if (!scroll_speed)
               return false;

            if (selection_ptr >= menu_list_size - 1
                  && !settings->menu.navigation.wraparound.enable)
               return false;

            if ((selection_ptr + (*scroll_speed)) < menu_list_size)
            {
               size_t idx  = selection_ptr + (*scroll_speed);
               bool scroll = true;
               menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx);
               menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll);
               menu_navigation_ctl(MENU_NAVIGATION_CTL_INCREMENT, NULL);
            }
            else
            {
               if (settings->menu.navigation.wraparound.enable)
               {
                  bool pending_push = false;
                  menu_navigation_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
               }
               else
               {
                  if (menu_list_size > 0)
                  {
                     menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_LAST,  NULL);
                     menu_navigation_ctl(MENU_NAVIGATION_CTL_INCREMENT, NULL);
                  }
               }
            }
            
            menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_INCREMENT, NULL);
         }
         break;
      case MENU_NAVIGATION_CTL_DECREMENT:
         {
            size_t idx             = 0;
            bool scroll            = true;
            settings_t *settings   = config_get_ptr();
            unsigned *scroll_speed = (unsigned*)data;
            size_t  menu_list_size = menu_entries_get_size();

            if (!scroll_speed)
               return false;

            if (selection_ptr == 0 
                  && !settings->menu.navigation.wraparound.enable)
               return false;

            if (selection_ptr >= *scroll_speed)
               idx = selection_ptr - *scroll_speed;
            else
            {
               idx  = menu_list_size - 1;
               if (!settings->menu.navigation.wraparound.enable)
                  idx = 0;
            }

            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx);
            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll);
            menu_navigation_ctl(MENU_NAVIGATION_CTL_DECREMENT, NULL);
            menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_DECREMENT, NULL);

         }
         break;
      case MENU_NAVIGATION_CTL_SET:
         menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_SET, data);
         break;
      case MENU_NAVIGATION_CTL_SET_LAST:
         {
            size_t  menu_list_size = menu_entries_get_size();
            size_t new_selection = menu_list_size - 1;
            menu_navigation_ctl(
                  MENU_NAVIGATION_CTL_SET_SELECTION, &new_selection);
            menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_SET_LAST, NULL);
         }
         break;
      case MENU_NAVIGATION_CTL_ASCEND_ALPHABET:
         {
            size_t i = 0, ptr;
            size_t *ptr_out        = (size_t*)&selection_ptr;
            size_t  menu_list_size = menu_entries_get_size();

            if (!scroll_index.size || !ptr_out)
               return false;

            ptr = *ptr_out;

            if (ptr == scroll_index.list[scroll_index.size - 1])
            {
               *ptr_out = menu_list_size - 1;
               menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_ASCEND_ALPHABET, ptr_out);
               return true;
            }

            while (i < scroll_index.size - 1
                  && scroll_index.list[i + 1] <= ptr)
               i++;
            *ptr_out = scroll_index.list[i + 1];

            if (*ptr_out >= menu_list_size)
               *ptr_out = menu_list_size - 1;

            menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_ASCEND_ALPHABET, ptr_out);
         }
         break;
      case MENU_NAVIGATION_CTL_DESCEND_ALPHABET:
         {
            size_t i = 0, ptr;
            size_t *ptr_out = (size_t*)&selection_ptr;

            if (!scroll_index.size || !ptr_out)
               return false;

            ptr = *ptr_out;

            if (ptr == 0)
               return false;

            i   = scroll_index.size - 1;

            while (i && scroll_index.list[i - 1] >= ptr)
               i--;
            *ptr_out = scroll_index.list[i - 1];

            menu_driver_ctl(
                  RARCH_MENU_CTL_NAVIGATION_DESCEND_ALPHABET, ptr_out);
         }
         break;
      case MENU_NAVIGATION_CTL_GET_SELECTION:
         {
            size_t *sel = (size_t*)data;
            if (!sel)
               return false;
            *sel = selection_ptr;
         }
         break;
      case MENU_NAVIGATION_CTL_SET_SELECTION:
         {
            size_t *sel = (size_t*)data;
            if (!sel)
               return false;
            selection_ptr = *sel;
         }
         break;
      case MENU_NAVIGATION_CTL_CLEAR_SCROLL_INDICES:
         scroll_index.size = 0;
         break;
      case MENU_NAVIGATION_CTL_ADD_SCROLL_INDEX:
         {
            size_t *sel = (size_t*)data;
            if (!sel)
               return false;
            scroll_index.list[scroll_index.size++] = *sel;
         }
         break;
      case MENU_NAVIGATION_CTL_GET_SCROLL_ACCEL:
         {
            size_t *sel = (size_t*)data;
            if (!sel)
               return false;
            *sel = scroll_acceleration;
         }
         break;
      case MENU_NAVIGATION_CTL_SET_SCROLL_ACCEL:
         {
            size_t *sel = (size_t*)data;
            if (!sel)
               return false;
            scroll_acceleration = *sel;
         }
         break;
      default:
      case MENU_NAVIGATION_CTL_NONE:
         break;
   }

   return true;
}
Exemplo n.º 14
0
static int menu_input_mouse_post_iterate(uint64_t *input_mouse,
      menu_file_list_cbs_t *cbs, unsigned action)
{
   size_t selection;
   unsigned header_height;
   settings_t *settings     = config_get_ptr();
   menu_input_t *menu_input = menu_input_get_ptr();

   *input_mouse = MOUSE_ACTION_NONE;

   menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection);

   if (!settings->menu.mouse.enable
#ifdef HAVE_OVERLAY
       || (settings->input.overlay_enable && input_overlay_is_alive())
#endif
       )
   {
      menu_input->mouse.wheeldown = false;
      menu_input->mouse.wheelup   = false;
      menu_input->mouse.oldleft   = false;
      menu_input->mouse.oldright  = false;
      return 0;
   }

   if (menu_input_mouse_state(MENU_MOUSE_LEFT_BUTTON))
   {
      if (!menu_input->mouse.oldleft)
      {
         menu_display_ctl(MENU_DISPLAY_CTL_HEADER_HEIGHT, &header_height);

         BIT64_SET(*input_mouse, MOUSE_ACTION_BUTTON_L);

         menu_input->mouse.oldleft = true;

         if ((unsigned)menu_input->mouse.y < header_height)
         {
            menu_entries_pop_stack(&selection, 0);
            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &selection);
            return 0;
         }
         if ((menu_input->mouse.ptr == selection) && cbs && cbs->action_select)
         {
            BIT64_SET(*input_mouse, MOUSE_ACTION_BUTTON_L_TOGGLE);
         }
         else if (menu_input->mouse.ptr <= (menu_entries_get_size() - 1))
         {
            BIT64_SET(*input_mouse, MOUSE_ACTION_BUTTON_L_SET_NAVIGATION);
         }
      }
   }
   else
      menu_input->mouse.oldleft = false;

   if (menu_input_mouse_state(MENU_MOUSE_RIGHT_BUTTON))
   {
      if (!menu_input->mouse.oldright)
      {
         menu_input->mouse.oldright = true;
         BIT64_SET(*input_mouse, MOUSE_ACTION_BUTTON_R);
      }
   }
   else
      menu_input->mouse.oldright = false;

   if (menu_input->mouse.wheeldown)
   {
      BIT64_SET(*input_mouse, MOUSE_ACTION_WHEEL_DOWN);
   }

   if (menu_input->mouse.wheelup)
   {
      BIT64_SET(*input_mouse, MOUSE_ACTION_WHEEL_UP);
   }

   return 0;
}
Exemplo n.º 15
0
static bool zarch_zui_gamepad_input(zui_t *zui,
      int *gamepad_index, int *list_first,
      unsigned skip)
{
   unsigned size          = menu_entries_get_size();
   unsigned cutoff_point  = size - 5;

   switch (zui->action)
   {
      case MENU_ACTION_LEFT:
         if (*gamepad_index == 0)
            break;

         *gamepad_index = *gamepad_index - 5;

         if (*gamepad_index < 0)
            *gamepad_index = 0;
         return true;
      case MENU_ACTION_RIGHT:
         if (*gamepad_index == (signed)(size-1))
            break;

         *gamepad_index = *gamepad_index + 5;

         if (*gamepad_index > (signed)(size-1))
            *gamepad_index   = (size -1);

         return true;
      case MENU_ACTION_UP:
         *gamepad_index = *gamepad_index - 1;

         if (*gamepad_index < 0) /* and wraparound enabled */
            *gamepad_index = size -1;
         else if (*gamepad_index >= (signed)cutoff_point) /* if greater than cutoff point, 
                                                don't scroll */
            return false;

         return true;
      case MENU_ACTION_DOWN:
         *gamepad_index = *gamepad_index + 1;

         if (*gamepad_index > (signed)(size - 1)) /* and wraparound enabled */
            *gamepad_index = 0;
         else if (*gamepad_index >= (signed)cutoff_point) /* if greater than cutoff point, 
                                                don't scroll */
            return false;
         return true;
      default:
         {
            *list_first += zui->mouse.wheel;
            if (*list_first < 0)
               *list_first = 0;
            if (*list_first > (int)cutoff_point)
               *list_first = cutoff_point;

            *list_first = MIN(MAX(*list_first, 0), cutoff_point - skip);
         }
         return false;
   }

   return false;
}
Exemplo n.º 16
0
static int menu_input_mouse_post_iterate(uint64_t *input_mouse,
      menu_file_list_cbs_t *cbs, unsigned action)
{
   settings_t *settings       = config_get_ptr();
   static bool mouse_oldleft  = false;
   static bool mouse_oldright = false;

   *input_mouse = MENU_MOUSE_ACTION_NONE;


   if (
         !settings->menu.mouse.enable 
#ifdef HAVE_OVERLAY
         || (settings->input.overlay_enable && input_overlay_is_alive(NULL))
#endif
         )
   {
      mouse_oldleft   = false;
      mouse_oldright  = false;
      return 0;
   }

   if (menu_input_mouse_state(MENU_MOUSE_LEFT_BUTTON))
   {
      if (!mouse_oldleft)
      {
         size_t selection;
         unsigned header_height;
         menu_input_t *menu_input = menu_input_get_ptr();

         menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection);
         header_height = menu_display_get_header_height();

         BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_BUTTON_L);

         mouse_oldleft = true;

         /* Back button */
         if ((unsigned)menu_input_mouse_state(MENU_MOUSE_X_AXIS) < header_height)
         {
            menu_entries_pop_stack(&selection, 0, 1);
            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &selection);
            return 0;
         }
         if ((menu_input->mouse.ptr == selection) && cbs && cbs->action_select)
         {
            BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_BUTTON_L_TOGGLE);
         }
         else if (menu_input->mouse.ptr <= (menu_entries_get_size() - 1))
         {
            BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_BUTTON_L_SET_NAVIGATION);
         }
      }
   }
   else
      mouse_oldleft = false;

   if (menu_input_mouse_state(MENU_MOUSE_RIGHT_BUTTON))
   {
      if (!mouse_oldright)
      {
         mouse_oldright = true;
         BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_BUTTON_R);
      }
   }
   else
      mouse_oldright = false;

   if (menu_input_mouse_state(MENU_MOUSE_WHEEL_DOWN))
   {
      BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_WHEEL_DOWN);
   }

   if (menu_input_mouse_state(MENU_MOUSE_WHEEL_UP))
   {
      BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_WHEEL_UP);
   }

   if (menu_input_mouse_state(MENU_MOUSE_HORIZ_WHEEL_DOWN))
   {
      BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_HORIZ_WHEEL_DOWN);
   }

   if (menu_input_mouse_state(MENU_MOUSE_HORIZ_WHEEL_UP))
   {
      BIT64_SET(*input_mouse, MENU_MOUSE_ACTION_HORIZ_WHEEL_UP);
   }

   return 0;
}
Exemplo n.º 17
0
/**
 * menu_iterate:
 * @input                    : input sample for this frame
 * @old_input                : input sample of the previous frame
 * @trigger_input            : difference' input sample - difference
 *                             between 'input' and 'old_input'
 *
 * Runs RetroArch menu for one frame.
 *
 * Returns: 0 on success, -1 if we need to quit out of the loop.
 **/
int generic_menu_iterate(void *data, void *userdata, enum menu_action action)
{
   menu_entry_t entry;
   enum action_iterate_type iterate_type;
   size_t selection               = 0;
   unsigned file_type             = 0;
   int ret                        = 0;
   uint32_t hash                  = 0;
   enum msg_hash_enums enum_idx   = MSG_UNKNOWN;
   const char *label              = NULL;
   menu_handle_t *menu            = (menu_handle_t*)data;

   menu_entries_get_last_stack(NULL, &label, &file_type, &enum_idx, NULL);

   if (!menu)
      return 0;
   if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection))
      return 0;

   menu->menu_state.msg[0]   = '\0';
   hash                      = msg_hash_calculate(label);
   iterate_type              = action_iterate_type(hash);

   menu_driver_set_binding_state(iterate_type == ITERATE_TYPE_BIND);

   if (     action != MENU_ACTION_NOOP
         || menu_entries_ctl(MENU_ENTRIES_CTL_NEEDS_REFRESH, NULL)
         || menu_display_get_update_pending())
   {
      BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER);
   }

   switch (iterate_type)
   {
      case ITERATE_TYPE_HELP:
         ret = menu_dialog_iterate(
               menu->menu_state.msg, sizeof(menu->menu_state.msg), label);
         BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
         BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
         if (ret == 1 || action == MENU_ACTION_OK)
         {
            BIT64_SET(menu->state, MENU_STATE_POP_STACK);
            menu_dialog_set_active(false);
         }

         if (action == MENU_ACTION_CANCEL)
         {
            BIT64_SET(menu->state, MENU_STATE_POP_STACK);
            menu_dialog_set_active(false);
         }
         break;
      case ITERATE_TYPE_BIND:
         {
            menu_input_ctx_bind_t bind;

            bind.s   = menu->menu_state.msg;
            bind.len = sizeof(menu->menu_state.msg);

            if (menu_input_key_bind_iterate(&bind))
            {
               menu_entries_pop_stack(&selection, 0, 0);
               menu_navigation_ctl(
                     MENU_NAVIGATION_CTL_SET_SELECTION, &selection);
            }
            else
               BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
         }
         break;
      case ITERATE_TYPE_INFO:
         {
            file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
            menu_file_list_cbs_t *cbs  =
               menu_entries_get_actiondata_at_offset(selection_buf, selection);

            if (cbs->enum_idx != MSG_UNKNOWN)
            {
               ret = menu_hash_get_help_enum(cbs->enum_idx,
                     menu->menu_state.msg, sizeof(menu->menu_state.msg));
            }
            else
            {
               unsigned type = 0;
               enum msg_hash_enums enum_idx = MSG_UNKNOWN;
               menu_entries_get_at_offset(selection_buf, selection,
                     NULL, NULL, &type, NULL, NULL);

               switch (type)
               {
                  case FILE_TYPE_FONT:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_FONT;
                     break;
                  case FILE_TYPE_RDB:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_RDB;
                     break;
                  case FILE_TYPE_OVERLAY:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_OVERLAY;
                     break;
                  case FILE_TYPE_CHEAT:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CHEAT;
                     break;
                  case FILE_TYPE_SHADER_PRESET:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_SHADER_PRESET;
                     break;
                  case FILE_TYPE_SHADER:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_SHADER;
                     break;
                  case FILE_TYPE_REMAP:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_REMAP;
                     break;
                  case FILE_TYPE_RECORD_CONFIG:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_RECORD_CONFIG;
                     break;
                  case FILE_TYPE_CURSOR:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CURSOR;
                     break;
                  case FILE_TYPE_CONFIG:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CONFIG;
                     break;
                  case FILE_TYPE_CARCHIVE:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_COMPRESSED_ARCHIVE;
                     break;
                  case FILE_TYPE_DIRECTORY:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
                     break;
                  case FILE_TYPE_VIDEOFILTER:            /* TODO/FIXME */
                  case FILE_TYPE_AUDIOFILTER:            /* TODO/FIXME */
                  case FILE_TYPE_SHADER_SLANG:           /* TODO/FIXME */
                  case FILE_TYPE_SHADER_GLSL:            /* TODO/FIXME */
                  case FILE_TYPE_SHADER_HLSL:            /* TODO/FIXME */
                  case FILE_TYPE_SHADER_CG:              /* TODO/FIXME */
                  case FILE_TYPE_SHADER_PRESET_GLSLP:    /* TODO/FIXME */
                  case FILE_TYPE_SHADER_PRESET_HLSLP:    /* TODO/FIXME */
                  case FILE_TYPE_SHADER_PRESET_CGP:      /* TODO/FIXME */
                  case FILE_TYPE_SHADER_PRESET_SLANGP:   /* TODO/FIXME */
                  case FILE_TYPE_PLAIN:
                     enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_PLAIN_FILE;
                     break;
                  default:
                     break;
               }

               if (enum_idx != MSG_UNKNOWN)
                  ret = menu_hash_get_help_enum(enum_idx,
                        menu->menu_state.msg, sizeof(menu->menu_state.msg));

            }
         }
         BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
         BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
         if (action == MENU_ACTION_OK || action == MENU_ACTION_CANCEL)
         {
            BIT64_SET(menu->state, MENU_STATE_POP_STACK);
         }
         menu_dialog_set_active(false);
         break;
      case ITERATE_TYPE_DEFAULT:
         /* FIXME: Crappy hack, needed for mouse controls
          * to not be completely broken in case we press back.
          *
          * We need to fix this entire mess, mouse controls
          * should not rely on a hack like this in order to work. */
         selection = MAX(MIN(selection, (menu_entries_get_size() - 1)), 0);

         menu_entry_get(&entry, 0, selection, NULL, false);
         ret = menu_entry_action(&entry, selection, (enum menu_action)action);

         if (ret)
            goto end;

         BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);

         /* Have to defer it so we let settings refresh. */
         menu_dialog_push();
         break;
   }

   BIT64_SET(menu->state, MENU_STATE_BLIT);

   if (BIT64_GET(menu->state, MENU_STATE_POP_STACK))
   {
      size_t new_selection_ptr = selection;
      menu_entries_pop_stack(&new_selection_ptr, 0, 0);
      menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &selection);
   }

   if (BIT64_GET(menu->state, MENU_STATE_POST_ITERATE))
      menu_input_post_iterate(&ret, action);

end:
   if (ret)
      return -1;
   return 0;
}
Exemplo n.º 18
0
static void xui_render(void *data, bool is_idle)
{
   size_t end, i, selection, fb_pitch;
   unsigned fb_width, fb_height;
   char title[PATH_MAX_LENGTH] = {0};
   const char *dir             = NULL;
   const char *label           = NULL;
   unsigned menu_type          = 0;
   uint64_t frame_count        = xui_frame_count;
   bool              msg_force = menu_display_get_msg_force();

   menu_display_get_fb_size(&fb_width, &fb_height,
         &fb_pitch);

   if (
         menu_entries_ctl(MENU_ENTRIES_CTL_NEEDS_REFRESH, NULL) 
         && menu_driver_is_alive()
         && !msg_force
      )
      return;

   menu_display_unset_framebuffer_dirty_flag();
   menu_animation_ctl(MENU_ANIMATION_CTL_CLEAR_ACTIVE, NULL);

   xui_render_background();

   if (XuiHandleIsValid(m_menutitle))
   {
      menu_animation_ctx_ticker_t ticker;
      menu_entries_get_title(title, sizeof(title));
      mbstowcs(strw_buffer, title, sizeof(strw_buffer) / sizeof(wchar_t));
      XuiTextElementSetText(m_menutitle, strw_buffer);

	  ticker.s        = title;
	  ticker.len      = RXUI_TERM_WIDTH(fb_width) - 3;
	  ticker.idx      = (unsigned int)frame_count / 15;
	  ticker.str      = title;
	  ticker.selected = true;

      menu_animation_ticker(&ticker);
   }

   if (XuiHandleIsValid(m_menutitle))
   {
      if (
            menu_entries_get_core_title(title, sizeof(title)) == 0)
      {
         mbstowcs(strw_buffer, title, sizeof(strw_buffer) / sizeof(wchar_t));
         XuiTextElementSetText(m_menutitlebottom, strw_buffer);
      }
   }

   end = menu_entries_get_size();
   for (i = 0; i < end; i++)
   {
      menu_entry_t entry;
      char *entry_path                     = NULL;
      char entry_value[PATH_MAX_LENGTH]    = {0};
      wchar_t msg_right[PATH_MAX_LENGTH]   = {0};
      wchar_t msg_left[PATH_MAX_LENGTH]    = {0};

      menu_entry_init(&entry);
      menu_entry_get(&entry, 0, i, NULL, true);

      menu_entry_get_value(&entry, entry_value, sizeof(entry_value));
      entry_path = menu_entry_get_path(&entry);

      mbstowcs(msg_left,  entry_path,  sizeof(msg_left)  / sizeof(wchar_t));
      mbstowcs(msg_right, entry_value, sizeof(msg_right) / sizeof(wchar_t));
      xui_set_list_text(i, msg_left, msg_right);

      menu_entry_free(&entry);
      if (!string_is_empty(entry_path))
         free(entry_path);
   }

   selection = menu_navigation_get_selection();

   XuiListSetCurSelVisible(m_menulist, selection);

   if (menu_input_dialog_get_display_kb())
   {
      char msg[1024]    = {0};
      const char *str   = menu_input_dialog_get_buffer();
      const char *label = menu_input_dialog_get_label_buffer();

      snprintf(msg, sizeof(msg), "%s\n%s", label, str);
      xui_render_messagebox(NULL, msg);			
   }
}
Exemplo n.º 19
0
bool menu_navigation_ctl(enum menu_navigation_ctl_state state, void *data)
{
   const menu_ctx_driver_t *driver = menu_ctx_driver_get_ptr();
   settings_t          *settings   = config_get_ptr();
   menu_navigation_t        *nav   = menu_navigation_get_ptr();
   size_t          menu_list_size  = menu_entries_get_size();
   size_t selection                = nav->selection_ptr;

   (void)settings;

   switch (state)
   {
      case MENU_NAVIGATION_CTL_CLEAR:
         {
            size_t idx         = 0;
            bool scroll        = true;
            bool *pending_push = (bool*)data;

            if (!pending_push)
               return false;

            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx);
            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll);
            if (driver->navigation_clear)
               driver->navigation_clear(*pending_push);
         }
         return true;
      case MENU_NAVIGATION_CTL_INCREMENT:
         {
            unsigned *scroll_speed = (unsigned*)data;

            if (!scroll_speed)
               return false;

            if (selection >= menu_list_size - 1
                  && !settings->menu.navigation.wraparound.enable)
               return false;

            if ((selection + (*scroll_speed)) < menu_list_size)
            {
               size_t idx  = selection + (*scroll_speed);
               bool scroll = true;
               menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx);
               menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll);
               menu_navigation_ctl(MENU_NAVIGATION_CTL_INCREMENT, NULL);
            }
            else
            {
               if (settings->menu.navigation.wraparound.enable)
               {
                  bool pending_push = false;
                  menu_navigation_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
               }
               else
               {
                  if (menu_list_size > 0)
                  {
                     menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_LAST,  NULL);
                     menu_navigation_ctl(MENU_NAVIGATION_CTL_INCREMENT, NULL);
                  }
               }
            }
            if (driver->navigation_increment)
               driver->navigation_increment();
         }
         return true;
      case MENU_NAVIGATION_CTL_DECREMENT:
         {
            size_t idx             = 0;
            bool scroll            = true;
            unsigned *scroll_speed = (unsigned*)data;

            if (!scroll_speed)
               return false;

            if (selection == 0 && !settings->menu.navigation.wraparound.enable)
               return false;

            if (selection >= *scroll_speed)
               idx = selection - *scroll_speed;
            else
            {
               idx  = menu_list_size - 1;
               if (!settings->menu.navigation.wraparound.enable)
                  idx = 0;
            }

            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx);
            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll);
            menu_navigation_ctl(MENU_NAVIGATION_CTL_DECREMENT, NULL);

            if (driver->navigation_decrement)
               driver->navigation_decrement();

         }
         return true;
      case MENU_NAVIGATION_CTL_SET:
         {
            bool *scroll = (bool*)data;

            if (!scroll)
               return false;

            if (driver->navigation_set)
               driver->navigation_set(*scroll);
         }
         return true;
      case MENU_NAVIGATION_CTL_SET_LAST:
         {
            size_t new_selection = menu_list_size - 1;
            menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &new_selection);

            if (driver->navigation_set_last)
               driver->navigation_set_last();
         }
         return true;
      case MENU_NAVIGATION_CTL_ASCEND_ALPHABET:
         {
            size_t i = 0, ptr;
            size_t *ptr_out = nav ? (size_t*)&nav->selection_ptr : NULL;

            if (!nav || !nav->scroll.indices.size || !ptr_out)
               return false;

            ptr = *ptr_out;

            if (ptr == nav->scroll.indices.list[nav->scroll.indices.size - 1])
               return false;

            while (i < nav->scroll.indices.size - 1
                  && nav->scroll.indices.list[i + 1] <= ptr)
               i++;
            *ptr_out = nav->scroll.indices.list[i + 1];

            if (driver->navigation_ascend_alphabet)
               driver->navigation_ascend_alphabet(ptr_out);
         }
         return true;
      case MENU_NAVIGATION_CTL_DESCEND_ALPHABET:
         {
            size_t i = 0, ptr;
            size_t *ptr_out = nav ? (size_t*)&nav->selection_ptr : NULL;

            if (!nav || !nav->scroll.indices.size || !ptr_out)
               return false;

            ptr = *ptr_out;

            if (ptr == 0)
               return false;

            i   = nav->scroll.indices.size - 1;

            while (i && nav->scroll.indices.list[i - 1] >= ptr)
               i--;
            *ptr_out = nav->scroll.indices.list[i - 1];

            if (driver->navigation_descend_alphabet)
               driver->navigation_descend_alphabet(ptr_out);
         }
         return true;
      case MENU_NAVIGATION_CTL_GET_SELECTION:
         {
            size_t *sel = (size_t*)data;
            if (!nav || !sel)
               return false;
            *sel = selection;
         }
         return true;
      case MENU_NAVIGATION_CTL_SET_SELECTION:
         {
            size_t *sel = (size_t*)data;
            if (!nav || !sel)
               return false;
            nav->selection_ptr = *sel;
         }
         return true;
      case MENU_NAVIGATION_CTL_CLEAR_SCROLL_INDICES:
         {
            if (!nav)
               return false;
            nav->scroll.indices.size = 0;
         }
         return true;
      case MENU_NAVIGATION_CTL_ADD_SCROLL_INDEX:
         {
            size_t *sel = (size_t*)data;
            if (!nav || !sel)
               return false;
            nav->scroll.indices.list[nav->scroll.indices.size++] = *sel;
         }
         return true;
      case MENU_NAVIGATION_CTL_GET_SCROLL_ACCEL:
         {
            size_t *sel = (size_t*)data;
            if (!nav || !sel)
               return false;
            *sel = nav->scroll.acceleration;
         }
         return true;
      case MENU_NAVIGATION_CTL_SET_SCROLL_ACCEL:
         {
            size_t *sel = (size_t*)data;
            if (!nav || !sel)
               return false;
            nav->scroll.acceleration = *sel;
         }
         return true;
   }

   return false;
}